diff --git a/src/Autopilot/xmlauto.cxx b/src/Autopilot/xmlauto.cxx index 6761cddf7..6d5428557 100644 --- a/src/Autopilot/xmlauto.cxx +++ b/src/Autopilot/xmlauto.cxx @@ -40,6 +40,20 @@ using std::cout; using std::endl; +FGXMLAutoInput::FGXMLAutoInput( SGPropertyNode_ptr node, double value, double offset, double scale) : + value(0.0), + abs(false), + property(NULL), + offset(NULL), + scale(NULL), + min(NULL), + max(NULL), + _condition(NULL) +{ + parse( node, value, offset, scale ); +} + + void FGXMLAutoInput::parse( SGPropertyNode_ptr node, double aValue, double aOffset, double aScale ) { value = aValue; @@ -151,7 +165,7 @@ double FGXMLAutoInput::get_value() return abs ? fabs(value) : value; } -FGXMLAutoComponent::FGXMLAutoComponent( SGPropertyNode * node ) : +FGXMLAutoComponent::FGXMLAutoComponent() : _condition( NULL ), enable_prop( NULL ), enable_value( NULL ), @@ -162,89 +176,6 @@ FGXMLAutoComponent::FGXMLAutoComponent( SGPropertyNode * node ) : debug(false), enabled( false ) { - int i; - SGPropertyNode *prop; - - 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 == "feedback-if-disabled" ) { - feedback_if_disabled = child->getBoolValue(); - - } else if ( cname == "debug" ) { - debug = child->getBoolValue(); - - } else if ( cname == "enable" ) { - if( (prop = child->getChild("condition")) != NULL ) { - _condition = sgReadCondition(child, prop); - } else { - if ( (prop = child->getChild( "prop" )) != NULL ) { - enable_prop = fgGetNode( prop->getStringValue(), true ); - } - - if ( (prop = child->getChild( "value" )) != NULL ) { - delete enable_value; - enable_value = new string(prop->getStringValue()); - } - } - if ( (prop = child->getChild( "honor-passive" )) != NULL ) { - honor_passive = prop->getBoolValue(); - } - - } else if ( cname == "input" ) { - - valueInput.push_back( new FGXMLAutoInput( child ) ); - - } else if ( cname == "reference" ) { - - referenceInput.push_back( new FGXMLAutoInput( child ) ); - - } else if ( cname == "output" ) { - // grab all and childs - int found = 0; - // backwards compatibility: allow elements - for( int i = 0; (prop = child->getChild("prop", i)) != NULL; i++ ) { - SGPropertyNode *tmp = fgGetNode( prop->getStringValue(), true ); - output_list.push_back( tmp ); - found++; - } - for( int i = 0; (prop = child->getChild("property", i)) != NULL; i++ ) { - SGPropertyNode *tmp = fgGetNode( prop->getStringValue(), true ); - output_list.push_back( tmp ); - found++; - } - - // no elements, text node of is property name - if( found == 0 ) - output_list.push_back( fgGetNode(child->getStringValue(), true ) ); - - } else if ( cname == "config" ) { - if( (prop = child->getChild("min")) != NULL ) { - uminInput.push_back( new FGXMLAutoInput( prop ) ); - } - if( (prop = child->getChild("u_min")) != NULL ) { - uminInput.push_back( new FGXMLAutoInput( prop ) ); - } - if( (prop = child->getChild("max")) != NULL ) { - umaxInput.push_back( new FGXMLAutoInput( prop ) ); - } - if( (prop = child->getChild("u_max")) != NULL ) { - umaxInput.push_back( new FGXMLAutoInput( prop ) ); - } - } else if ( cname == "min" ) { - uminInput.push_back( new FGXMLAutoInput( child ) ); - } else if ( cname == "u_min" ) { - uminInput.push_back( new FGXMLAutoInput( child ) ); - } else if ( cname == "max" ) { - umaxInput.push_back( new FGXMLAutoInput( child ) ); - } else if ( cname == "u_max" ) { - umaxInput.push_back( new FGXMLAutoInput( child ) ); - } - } } FGXMLAutoComponent::~FGXMLAutoComponent() @@ -252,6 +183,111 @@ FGXMLAutoComponent::~FGXMLAutoComponent() delete enable_value; } +void FGXMLAutoComponent::parseNode(SGPropertyNode* aNode) +{ + SGPropertyNode *prop; + for (int i = 0; i < aNode->nChildren(); ++i ) { + SGPropertyNode *child = aNode->getChild(i); + string cname(child->getName()); + + if (parseNodeHook(cname, child)) { + // derived class handled it, fine + } else if ( cname == "name" ) { + name = child->getStringValue(); + } else if ( cname == "feedback-if-disabled" ) { + feedback_if_disabled = child->getBoolValue(); + } else if ( cname == "debug" ) { + debug = child->getBoolValue(); + } else if ( cname == "enable" ) { + if( (prop = child->getChild("condition")) != NULL ) { + _condition = sgReadCondition(child, prop); + } else { + if ( (prop = child->getChild( "prop" )) != NULL ) { + enable_prop = fgGetNode( prop->getStringValue(), true ); + } + + if ( (prop = child->getChild( "value" )) != NULL ) { + delete enable_value; + enable_value = new string(prop->getStringValue()); + } + } + if ( (prop = child->getChild( "honor-passive" )) != NULL ) { + honor_passive = prop->getBoolValue(); + } + } else if ( cname == "input" ) { + valueInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "reference" ) { + referenceInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "output" ) { + // grab all and childs + int found = 0; + // backwards compatibility: allow elements + for( int i = 0; (prop = child->getChild("prop", i)) != NULL; i++ ) { + SGPropertyNode *tmp = fgGetNode( prop->getStringValue(), true ); + output_list.push_back( tmp ); + found++; + } + for( int i = 0; (prop = child->getChild("property", i)) != NULL; i++ ) { + SGPropertyNode *tmp = fgGetNode( prop->getStringValue(), true ); + output_list.push_back( tmp ); + found++; + } + + // no elements, text node of is property name + if( found == 0 ) + output_list.push_back( fgGetNode(child->getStringValue(), true ) ); + } else if ( cname == "config" ) { + parseConfig(child); + } else if ( cname == "min" ) { + uminInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "u_min" ) { + uminInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "max" ) { + umaxInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "u_max" ) { + umaxInput.push_back( new FGXMLAutoInput( child ) ); + } else { + SG_LOG(SG_AUTOPILOT, SG_ALERT, "malformed autopilot definition - unrecognized node:" + << cname << " in section " << name); + throw sg_io_exception("XMLAuto: unrecognized component node:" + cname, "Section=" + name); + } + } // of top-level iteration +} + +void FGXMLAutoComponent::parseConfig(SGPropertyNode* aConfig) +{ + for (int i = 0; i < aConfig->nChildren(); ++i ) { + SGPropertyNode *child = aConfig->getChild(i); + string cname(child->getName()); + + if (parseConfigHook(cname, child)) { + // derived class handled it, fine + } else if ( cname == "min" ) { + uminInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "u_min" ) { + uminInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "max" ) { + umaxInput.push_back( new FGXMLAutoInput( child ) ); + } else if ( cname == "u_max" ) { + umaxInput.push_back( new FGXMLAutoInput( child ) ); + } else { + SG_LOG(SG_AUTOPILOT, SG_ALERT, "malformed autopilot definition - unrecognized config node:" + << cname << " in section " << name); + throw sg_io_exception("XMLAuto: unrecognized config node:" + cname, "Section=" + name); + } + } // of config iteration +} + +bool FGXMLAutoComponent::parseNodeHook(const string& aName, SGPropertyNode* aNode) +{ + return false; +} + +bool FGXMLAutoComponent::parseConfigHook(const string& aName, SGPropertyNode* aNode) +{ + return false; +} + bool FGXMLAutoComponent::isPropertyEnabled() { if( _condition ) @@ -289,7 +325,7 @@ double FGXMLAutoComponent::clamp( double value ) } FGPIDController::FGPIDController( SGPropertyNode *node ): - FGXMLAutoComponent( node ), + FGXMLAutoComponent(), alpha( 0.1 ), beta( 1.0 ), gamma( 0.0 ), @@ -300,46 +336,32 @@ FGPIDController::FGPIDController( SGPropertyNode *node ): desiredTs( 0.0 ), elapsedTime( 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 == "config" ) { - SGPropertyNode *config; - - if ( (config = child->getChild( "Ts" )) != NULL ) { - desiredTs = config->getDoubleValue(); - } - - Kp.push_back( new FGXMLAutoInput( child->getChild( "Kp" ) ) ); - Ti.push_back( new FGXMLAutoInput( child->getChild( "Ti" ) ) ); - Td.push_back( new FGXMLAutoInput( child->getChild( "Td" ) ) ); - - config = child->getChild( "beta" ); - if ( config != NULL ) { - beta = config->getDoubleValue(); - } - - config = child->getChild( "alpha" ); - if ( config != NULL ) { - alpha = config->getDoubleValue(); - } - - config = child->getChild( "gamma" ); - if ( config != NULL ) { - gamma = config->getDoubleValue(); - } - - } else { - SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in autopilot config logic" ); - if ( get_name().length() ) { - SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << get_name() ); - } - } - } + parseNode(node); } +bool FGPIDController::parseConfigHook(const string& aName, SGPropertyNode* aNode) +{ + if (aName == "Ts") { + desiredTs = aNode->getDoubleValue(); + } else if (aName == "Kp") { + Kp.push_back( new FGXMLAutoInput(aNode) ); + } else if (aName == "Ti") { + Ti.push_back( new FGXMLAutoInput(aNode) ); + } else if (aName == "Td") { + Td.push_back( new FGXMLAutoInput(aNode) ); + } else if (aName == "beta") { + beta = aNode->getDoubleValue(); + } else if (aName == "alpha") { + alpha = aNode->getDoubleValue(); + } else if (aName == "gamma") { + gamma = aNode->getDoubleValue(); + } else { + // unhandled by us, let the base class try it + return false; + } + + return true; +} /* * Roy Vegard Ovesen: @@ -512,26 +534,25 @@ void FGPIDController::update( double dt ) { FGPISimpleController::FGPISimpleController( SGPropertyNode *node ): - FGXMLAutoComponent( node ), + FGXMLAutoComponent(), int_sum( 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 == "config" ) { - Kp.push_back( new FGXMLAutoInput( child->getChild( "Kp" ) ) ); - Ki.push_back( new FGXMLAutoInput( child->getChild( "Ki" ) ) ); - } else { - SG_LOG( SG_AUTOPILOT, SG_WARN, "Error in autopilot config logic" ); - if ( get_name().length() ) { - SG_LOG( SG_AUTOPILOT, SG_WARN, "Section = " << get_name() ); - } - } - } + parseNode(node); } +bool FGPISimpleController::parseConfigHook(const string& aName, SGPropertyNode* aNode) +{ + if (aName == "Kp") { + Kp.push_back( new FGXMLAutoInput(aNode) ); + } else if (aName == "Ki") { + Ki.push_back( new FGXMLAutoInput(aNode) ); + } else { + // unhandled by us, let the base class try it + return false; + } + + return true; +} void FGPISimpleController::update( double dt ) { @@ -573,19 +594,23 @@ void FGPISimpleController::update( double dt ) { FGPredictor::FGPredictor ( SGPropertyNode *node ): - FGXMLAutoComponent( node ), + FGXMLAutoComponent(), average(0.0) { - int i; - for ( i = 0; i < node->nChildren(); ++i ) { - SGPropertyNode *child = node->getChild(i); - string cname = child->getName(); - if ( cname == "seconds" ) { - seconds.push_back( new FGXMLAutoInput( child, 0 ) ); - } else if ( cname == "filter-gain" ) { - filter_gain.push_back( new FGXMLAutoInput( child, 0 ) ); - } - } + parseNode(node); +} + +bool FGPredictor::parseNodeHook(const string& aName, SGPropertyNode* aNode) +{ + if (aName == "seconds") { + seconds.push_back( new FGXMLAutoInput( aNode, 0 ) ); + } else if (aName == "filter-gain") { + filter_gain.push_back( new FGXMLAutoInput( aNode, 0 ) ); + } else { + return false; + } + + return true; } void FGPredictor::update( double dt ) { @@ -634,47 +659,52 @@ void FGPredictor::update( double dt ) { FGDigitalFilter::FGDigitalFilter(SGPropertyNode *node): - FGXMLAutoComponent( node ), + FGXMLAutoComponent(), filterType(none) { - int i; - for ( i = 0; i < node->nChildren(); ++i ) { - SGPropertyNode *child = node->getChild(i); - string cname = child->getName(); - string cval = child->getStringValue(); - if ( cname == "type" ) { - if ( cval == "exponential" ) { - filterType = exponential; - } else if (cval == "double-exponential") { - filterType = doubleExponential; - } else if (cval == "moving-average") { - filterType = movingAverage; - } else if (cval == "noise-spike") { - filterType = noiseSpike; - } else if (cval == "gain") { - filterType = gain; - } else if (cval == "reciprocal") { - filterType = reciprocal; - } - } else if ( cname == "filter-time" ) { - TfInput.push_back( new FGXMLAutoInput( child, 1.0 ) ); - if( filterType == none ) filterType = exponential; - } else if ( cname == "samples" ) { - samplesInput.push_back( new FGXMLAutoInput( child, 1 ) ); - if( filterType == none ) filterType = movingAverage; - } else if ( cname == "max-rate-of-change" ) { - rateOfChangeInput.push_back( new FGXMLAutoInput( child, 1 ) ); - if( filterType == none ) filterType = noiseSpike; - } else if ( cname == "gain" ) { - gainInput.push_back( new FGXMLAutoInput( child, 1 ) ); - if( filterType == none ) filterType = gain; - } - } + parseNode(node); output.resize(2, 0.0); input.resize(samplesInput.get_value() + 1, 0.0); } + +bool FGDigitalFilter::parseNodeHook(const string& aName, SGPropertyNode* aNode) +{ + if (aName == "type" ) { + string val(aNode->getStringValue()); + if ( val == "exponential" ) { + filterType = exponential; + } else if (val == "double-exponential") { + filterType = doubleExponential; + } else if (val == "moving-average") { + filterType = movingAverage; + } else if (val == "noise-spike") { + filterType = noiseSpike; + } else if (val == "gain") { + filterType = gain; + } else if (val == "reciprocal") { + filterType = reciprocal; + } + } else if (aName == "filter-time" ) { + TfInput.push_back( new FGXMLAutoInput( aNode, 1.0 ) ); + if( filterType == none ) filterType = exponential; + } else if (aName == "samples" ) { + samplesInput.push_back( new FGXMLAutoInput( aNode, 1 ) ); + if( filterType == none ) filterType = movingAverage; + } else if (aName == "max-rate-of-change" ) { + rateOfChangeInput.push_back( new FGXMLAutoInput( aNode, 1 ) ); + if( filterType == none ) filterType = noiseSpike; + } else if (aName == "gain" ) { + gainInput.push_back( new FGXMLAutoInput( aNode, 1 ) ); + if( filterType == none ) filterType = gain; + } else { + return false; // not handled by us, let the base class try + } + + return true; +} + void FGDigitalFilter::update(double dt) { if ( isPropertyEnabled() ) { @@ -795,9 +825,9 @@ void FGXMLAutopilot::init() { " details."); exit(-1); } - } catch (const sg_exception&) { + } catch (const sg_exception& e) { SG_LOG( SG_ALL, SG_ALERT, "Failed to load autopilot configuration: " - << config.str() ); + << config.str() << ":" << e.getMessage() ); } } else { diff --git a/src/Autopilot/xmlauto.hxx b/src/Autopilot/xmlauto.hxx index bbe122631..3f68fb20c 100644 --- a/src/Autopilot/xmlauto.hxx +++ b/src/Autopilot/xmlauto.hxx @@ -24,30 +24,16 @@ #ifndef _XMLAUTO_HXX #define _XMLAUTO_HXX 1 -#ifndef __cplusplus -# error This library requires C++ -#endif - -#ifdef HAVE_CONFIG_H -# include -#endif - #include #include #include #include -using std::string; -using std::vector; -using std::deque; - #include #include #include -#include
- class FGXMLAutoInput : public SGReferenced { private: @@ -61,18 +47,8 @@ private: SGSharedPtr _condition; public: - FGXMLAutoInput( SGPropertyNode_ptr node = NULL, double value = 0.0, double offset = 0.0, double scale = 1.0 ) : - value(0.0), - abs(false), - property(NULL), - offset(NULL), - scale(NULL), - min(NULL), - max(NULL), - _condition(NULL) { - parse( node, value, offset, scale ); - } - + FGXMLAutoInput( SGPropertyNode_ptr node = NULL, double value = 0.0, double offset = 0.0, double scale = 1.0 ); + void parse( SGPropertyNode_ptr, double value = 0.0, double offset = 0.0, double scale = 1.0 ); /* get the value of this input, apply scale and offset and clipping */ @@ -95,7 +71,7 @@ public: }; -class FGXMLAutoInputList : public vector > { +class FGXMLAutoInputList : public std::vector > { public: FGXMLAutoInput * get_active() { for (iterator it = begin(); it != end(); ++it) { @@ -119,16 +95,16 @@ class FGXMLAutoInputList : public vector > { class FGXMLAutoComponent : public SGReferenced { private: - vector output_list; + std::vector output_list; SGSharedPtr _condition; SGPropertyNode_ptr enable_prop; - string * enable_value; + std::string * enable_value; SGPropertyNode_ptr passive_mode; bool honor_passive; - string name; + std::string name; /* Feed back output property to input property if this filter is disabled. This is for multi-stage @@ -141,6 +117,31 @@ private: void do_feedback_if_disabled(); protected: + FGXMLAutoComponent(); + + /* + * Parse a component specification read from a property-list. + * Calls the hook methods below to allow derived classes to + * specialise parsing bevaiour. + */ + void parseNode(SGPropertyNode* aNode); + + /** + * Helper to parse the config section + */ + void parseConfig(SGPropertyNode* aConfig); + + /* + * Over-rideable hook method to allow derived classes to refine top-level + * node parsing. Return true if the node was handled, false otherwise. + */ + virtual bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode); + + /** + * Over-rideable hook method to allow derived classes to refine config + * node parsing. Return true if the node was handled, false otherwise. + */ + virtual bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode); FGXMLAutoInputList valueInput; FGXMLAutoInputList referenceInput; @@ -156,13 +157,12 @@ protected: } public: - - FGXMLAutoComponent( SGPropertyNode *node); + virtual ~FGXMLAutoComponent(); virtual void update (double dt)=0; - inline const string& get_name() { return name; } + inline const std::string& get_name() { return name; } double clamp( double value ); @@ -173,7 +173,7 @@ public: // helpful for things like flight directors which position // their vbars from the autopilot computations. if ( honor_passive && passive_mode->getBoolValue() ) return; - for( vector ::iterator it = output_list.begin(); it != output_list.end(); ++it) + for( std::vector ::iterator it = output_list.begin(); it != output_list.end(); ++it) (*it)->setDoubleValue( clamp( value ) ); } @@ -252,7 +252,9 @@ private: double desiredTs; // desired sampling interval (sec) double elapsedTime; // elapsed time (sec) - + +protected: + bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode); public: @@ -279,6 +281,8 @@ private: FGXMLAutoInputList Ki; double int_sum; +protected: + bool parseConfigHook(const std::string& aName, SGPropertyNode* aNode); public: @@ -301,6 +305,9 @@ private: FGXMLAutoInputList seconds; FGXMLAutoInputList filter_gain; +protected: + bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode); + public: FGPredictor( SGPropertyNode *node ); ~FGPredictor() {} @@ -329,12 +336,15 @@ private: FGXMLAutoInputList gainInput; // FGXMLAutoInputList TfInput; // Filter time [s] - deque output; - deque input; + std::deque output; + std::deque input; enum filterTypes { exponential, doubleExponential, movingAverage, noiseSpike, gain, reciprocal, none }; filterTypes filterType; +protected: + bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode); + public: FGDigitalFilter(SGPropertyNode *node); ~FGDigitalFilter() {} @@ -365,7 +375,7 @@ public: protected: - typedef vector > comp_list; + typedef std::vector > comp_list; private: diff --git a/src/Instrumentation/KLN89/kln89.cxx b/src/Instrumentation/KLN89/kln89.cxx index 4722e9653..da1134bea 100644 --- a/src/Instrumentation/KLN89/kln89.cxx +++ b/src/Instrumentation/KLN89/kln89.cxx @@ -46,10 +46,90 @@ #include #include
#include +#include #include using std::cout; +// Command callbacks for FlightGear + +static bool do_kln89_msg_pressed(const SGPropertyNode* arg) { + //cout << "do_kln89_msg_pressed called!\n"; + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->MsgPressed(); + return(true); +} + +static bool do_kln89_obs_pressed(const SGPropertyNode* arg) { + //cout << "do_kln89_obs_pressed called!\n"; + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->OBSPressed(); + return(true); +} + +static bool do_kln89_alt_pressed(const SGPropertyNode* arg) { + //cout << "do_kln89_alt_pressed called!\n"; + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->AltPressed(); + return(true); +} + +static bool do_kln89_nrst_pressed(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->NrstPressed(); + return(true); +} + +static bool do_kln89_dto_pressed(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->DtoPressed(); + return(true); +} + +static bool do_kln89_clr_pressed(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->ClrPressed(); + return(true); +} + +static bool do_kln89_ent_pressed(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->EntPressed(); + return(true); +} + +static bool do_kln89_crsr_pressed(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->CrsrPressed(); + return(true); +} + +static bool do_kln89_knob1left1(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->Knob1Left1(); + return(true); +} + +static bool do_kln89_knob1right1(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->Knob1Right1(); + return(true); +} + +static bool do_kln89_knob2left1(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->Knob2Left1(); + return(true); +} + +static bool do_kln89_knob2right1(const SGPropertyNode* arg) { + KLN89* gps = (KLN89*)globals->get_subsystem("kln89"); + gps->Knob2Right1(); + return(true); +} + +// End command callbacks + KLN89::KLN89(RenderArea2D* instrument) : DCLGPS(instrument) { _mode = KLN89_MODE_DISP; @@ -77,27 +157,28 @@ KLN89::KLN89(RenderArea2D* instrument) _pixelated = false; // Cyclic pages - GPSPage* apt_page = new KLN89AptPage(this); + _pages.clear(); + KLN89Page* apt_page = new KLN89AptPage(this); _pages.push_back(apt_page); - GPSPage* vor_page = new KLN89VorPage(this); + KLN89Page* vor_page = new KLN89VorPage(this); _pages.push_back(vor_page); - GPSPage* ndb_page = new KLN89NDBPage(this); + KLN89Page* ndb_page = new KLN89NDBPage(this); _pages.push_back(ndb_page); - GPSPage* int_page = new KLN89IntPage(this); + KLN89Page* int_page = new KLN89IntPage(this); _pages.push_back(int_page); - GPSPage* usr_page = new KLN89UsrPage(this); + KLN89Page* usr_page = new KLN89UsrPage(this); _pages.push_back(usr_page); - GPSPage* act_page = new KLN89ActPage(this); + KLN89Page* act_page = new KLN89ActPage(this); _pages.push_back(act_page); - GPSPage* nav_page = new KLN89NavPage(this); + KLN89Page* nav_page = new KLN89NavPage(this); _pages.push_back(nav_page); - GPSPage* fpl_page = new KLN89FplPage(this); + KLN89Page* fpl_page = new KLN89FplPage(this); _pages.push_back(fpl_page); - GPSPage* cal_page = new KLN89CalPage(this); + KLN89Page* cal_page = new KLN89CalPage(this); _pages.push_back(cal_page); - GPSPage* set_page = new KLN89SetPage(this); + KLN89Page* set_page = new KLN89SetPage(this); _pages.push_back(set_page); - GPSPage* oth_page = new KLN89OthPage(this); + KLN89Page* oth_page = new KLN89OthPage(this); _pages.push_back(oth_page); _nPages = _pages.size(); _curPage = 0; @@ -196,6 +277,23 @@ void KLN89::unbind() { DCLGPS::unbind(); } +void KLN89::init() { + globals->get_commands()->addCommand("kln89_msg_pressed", do_kln89_msg_pressed); + globals->get_commands()->addCommand("kln89_obs_pressed", do_kln89_obs_pressed); + globals->get_commands()->addCommand("kln89_alt_pressed", do_kln89_alt_pressed); + globals->get_commands()->addCommand("kln89_nrst_pressed", do_kln89_nrst_pressed); + globals->get_commands()->addCommand("kln89_dto_pressed", do_kln89_dto_pressed); + globals->get_commands()->addCommand("kln89_clr_pressed", do_kln89_clr_pressed); + globals->get_commands()->addCommand("kln89_ent_pressed", do_kln89_ent_pressed); + globals->get_commands()->addCommand("kln89_crsr_pressed", do_kln89_crsr_pressed); + globals->get_commands()->addCommand("kln89_knob1left1", do_kln89_knob1left1); + globals->get_commands()->addCommand("kln89_knob1right1", do_kln89_knob1right1); + globals->get_commands()->addCommand("kln89_knob2left1", do_kln89_knob2left1); + globals->get_commands()->addCommand("kln89_knob2right1", do_kln89_knob2right1); + + DCLGPS::init(); +} + void KLN89::update(double dt) { // Run any positional calc's required first DCLGPS::update(dt); @@ -476,7 +574,7 @@ void KLN89::NrstPressed() { void KLN89::AltPressed() {} void KLN89::OBSPressed() { - DCLGPS::OBSPressed(); + ToggleOBSMode(); if(_obsMode) { // if(ORS 02) _mode = KLN89_MODE_CRSR; @@ -494,6 +592,10 @@ void KLN89::MsgPressed() { _dispMsg = !_dispMsg; } +void KLN89::ToggleOBSMode() { + DCLGPS::ToggleOBSMode(); +} + void KLN89::DrawBar(int page) { int px = 1 + (page * 15); int py = 1; diff --git a/src/Instrumentation/KLN89/kln89.hxx b/src/Instrumentation/KLN89/kln89.hxx index 44f0ee09a..26dcccd3d 100644 --- a/src/Instrumentation/KLN89/kln89.hxx +++ b/src/Instrumentation/KLN89/kln89.hxx @@ -31,6 +31,8 @@ #include #include "kln89_page.hxx" +class KLN89Page; + const int KLN89MapScales[2][21] = {{1, 2, 3, 5, 7, 10, 12, 15, 17, 20, 25, 30, 40, 60, 80, 100, 120, 160, 240, 320, 500}, {2, 4, 6, 9, 13, 18, 22, 28, 32, 37, 46, 55, 75, 110, 150, 185, 220, 300, 440, 600, 925}}; @@ -48,6 +50,9 @@ const char* KLN89TimeCodes[20] = { "UTC", "GST", "GDT", "ATS", "ATD", "EST", "ED typedef map airport_id_str_map_type; typedef airport_id_str_map_type::iterator airport_id_str_map_iterator; +typedef vector kln89_page_list_type; +typedef kln89_page_list_type::iterator kln89_page_list_itr; + class KLN89 : public DCLGPS { friend class KLN89Page; @@ -71,6 +76,7 @@ public: void bind(); void unbind(); + void init(); void update(double dt); inline void SetTurnAnticipation(bool b) { _turnAnticipationEnabled = b; } @@ -100,6 +106,8 @@ public: void CreateDefaultFlightPlans(); private: + void ToggleOBSMode(); + //----------------------- Drawing functions which take CHARACTER units ------------------------- // Render string s in display field field at position x, y // WHERE POSITION IS IN CHARACTER UNITS! @@ -192,16 +200,26 @@ private: // Set gap to true to get a space between A and 9 when wrapping, set wrap to false to disable wrap. char IncChar(char c, bool gap = false, bool wrap = true); char DecChar(char c, bool gap = false, bool wrap = true); + + // ==================== Page organisation stuff ============= + // The list of cyclical pages that the user can cycle through + kln89_page_list_type _pages; + + // The currently active page + KLN89Page* _activePage; + // And a facility to save the immediately preceeding active page + KLN89Page* _lastActivePage; // Hackish int _entJump; // The page to jump back to if ent is pressed. -1 indicates no jump bool _entRestoreCrsr; // Indicates that pressing ENT at this point should restore cursor mode - // Misc pages + // Misc pages that aren't in the cyclic list. // Direct To - GPSPage* _dir_page; + KLN89Page* _dir_page; // Nearest - GPSPage* _nrst_page; + KLN89Page* _nrst_page; + // ====================== end of page stuff =================== // Moving-map display stuff int _mapOrientation; // 0 => North (true) up, 1 => DTK up, 2 => TK up, 3 => heading up (only when connected to external heading source). diff --git a/src/Instrumentation/KLN89/kln89_page.cxx b/src/Instrumentation/KLN89/kln89_page.cxx index f278cd4af..d3e5b8d4b 100644 --- a/src/Instrumentation/KLN89/kln89_page.cxx +++ b/src/Instrumentation/KLN89/kln89_page.cxx @@ -24,11 +24,11 @@ #include "kln89_page.hxx" #include
-KLN89Page::KLN89Page(KLN89* parent) -: GPSPage(parent) { - _kln89 = (KLN89*)parent; +KLN89Page::KLN89Page(KLN89* parent) { + _kln89 = parent; _entInvert = false; _to_flag = true; + _subPage = 0; } KLN89Page::~KLN89Page() { @@ -74,14 +74,14 @@ void KLN89Page::Update(double dt) { } } _kln89->DrawText((_kln89->GetDistVelUnitsSI() ? "km" : "nm"), 1, 4, 3); - GPSWaypoint* awp = _parent->GetActiveWaypoint(); + GPSWaypoint* awp = _kln89->GetActiveWaypoint(); if(_kln89->_navFlagged) { _kln89->DrawText("--.-", 1, 0 ,3); // Only nav1 still gets speed drawn if nav is flagged - not ACT if(!nav1) _kln89->DrawText("------", 1, 0, 2); } else { char buf[8]; - float f = _parent->GetDistToActiveWaypoint() * (_kln89->GetDistVelUnitsSI() ? 0.001 : SG_METER_TO_NM); + float f = _kln89->GetDistToActiveWaypoint() * (_kln89->GetDistVelUnitsSI() ? 0.001 : SG_METER_TO_NM); snprintf(buf, 5, (f >= 100.0 ? "%4.0f" : "%4.1f"), f); string s = buf; _kln89->DrawText(s, 1, 4 - s.size(), 3, true); @@ -132,7 +132,9 @@ void KLN89Page::Knob1Right1() { void KLN89Page::Knob2Left1() { if(_kln89->_mode != KLN89_MODE_CRSR && !fgGetBool("/instrumentation/kln89/scan-pull")) { - GPSPage::Knob2Left1(); + _kln89->_activePage->LooseFocus(); + _subPage--; + if(_subPage < 0) _subPage = _nSubPages - 1; } else { if(_uLinePos == 0 && _kln89->_obsMode) { _kln89->_obsHeading--; @@ -146,7 +148,9 @@ void KLN89Page::Knob2Left1() { void KLN89Page::Knob2Right1() { if(_kln89->_mode != KLN89_MODE_CRSR && !fgGetBool("/instrumentation/kln89/scan-pull")) { - GPSPage::Knob2Right1(); + _kln89->_activePage->LooseFocus(); + _subPage++; + if(_subPage >= _nSubPages) _subPage = 0; } else { if(_uLinePos == 0 && _kln89->_obsMode) { _kln89->_obsHeading++; @@ -203,3 +207,12 @@ void KLN89Page::SetId(const string& s) { const string& KLN89Page::GetId() { return(_id); } + +// TODO - this function probably shouldn't be here - FG almost certainly has better handling +// of this somewhere already. +string KLN89Page::GPSitoa(int n) { + char buf[6]; + snprintf(buf, 6, "%i", n); + string s = buf; + return(s); +} diff --git a/src/Instrumentation/KLN89/kln89_page.hxx b/src/Instrumentation/KLN89/kln89_page.hxx index 741942e3d..a4e686ab8 100644 --- a/src/Instrumentation/KLN89/kln89_page.hxx +++ b/src/Instrumentation/KLN89/kln89_page.hxx @@ -29,7 +29,7 @@ class KLN89; -class KLN89Page : public GPSPage { +class KLN89Page { public: KLN89Page(KLN89* parent); @@ -51,10 +51,15 @@ public: virtual void OBSPressed(); virtual void MsgPressed(); - // See base class comments for this. + // Sometimes a page needs to maintain state for some return paths, + // but change it for others. The CleanUp function can be used for + // changing state for non-ENT return paths in conjunction with + // GPS::_cleanUpPage virtual void CleanUp(); - // ditto + // The LooseFocus function is called when a page or subpage looses focus + // and allows pages to clean up state that is maintained whilst focus is + // retained, but lost on return. virtual void LooseFocus(); inline void SetEntInvert(bool b) { _entInvert = b; } @@ -63,9 +68,21 @@ public: virtual void SetId(const string& s); virtual const string& GetId(); + inline int GetSubPage() { return(_subPage); } + + inline int GetNSubPages() { return(_nSubPages); } + + inline const string& GetName() { return(_name); } + protected: + KLN89* _kln89; + string _name; // eg. "APT", "NAV" etc + int _nSubPages; + // _subpage is zero based + int _subPage; // The subpage gets remembered when other pages are displayed + // Underline position in cursor mode is not persistant when subpage is changed - hence we only need one variable per page for it. // Note that pos 0 is special - this is the leg pos in field 1, so pos will normally be set to 1 when crsr is pressed. // Also note that in general it doesn't seem to wrap. @@ -88,6 +105,9 @@ protected: double _scratchpadTimer; // Used for displaying the scratchpad messages for the right amount of time. string _scratchpadLine1; string _scratchpadLine2; + + // TODO - remove this function from this class and use a built in method instead. + string GPSitoa(int n); }; #endif // _KLN89_PAGE_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_act.hxx b/src/Instrumentation/KLN89/kln89_page_act.hxx index 4a1b04195..016fd3fdd 100644 --- a/src/Instrumentation/KLN89/kln89_page_act.hxx +++ b/src/Instrumentation/KLN89/kln89_page_act.hxx @@ -52,13 +52,13 @@ private: GPSWaypoint* _actWp; // The actual ACT page that gets displayed... - GPSPage* _actPage; + KLN89Page* _actPage; // ...which points to one of the below. - GPSPage* _aptPage; - GPSPage* _vorPage; - GPSPage* _ndbPage; - GPSPage* _intPage; - GPSPage* _usrPage; + KLN89Page* _aptPage; + KLN89Page* _vorPage; + KLN89Page* _ndbPage; + KLN89Page* _intPage; + KLN89Page* _usrPage; }; #endif // _KLN89_PAGE_ACT_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_fpl.cxx b/src/Instrumentation/KLN89/kln89_page_fpl.cxx index 2b4c350cc..86e6178c7 100644 --- a/src/Instrumentation/KLN89/kln89_page_fpl.cxx +++ b/src/Instrumentation/KLN89/kln89_page_fpl.cxx @@ -144,7 +144,7 @@ void KLN89FplPage::Update(double dt) { //----------------------------------------- end active FP copy ------------------------------------------------ // Recalculate which waypoint is displayed at the top of the list if required (generally if this page has lost focus). - int idx = _parent->GetActiveWaypointIndex(); + int idx = _kln89->GetActiveWaypointIndex(); if(_resetFplPos0) { if(waylist.size() <= 1) { _fplPos = 0; @@ -679,7 +679,7 @@ void KLN89FplPage::LooseFocus() { void KLN89FplPage::EntPressed() { if(_delFP) { - _parent->ClearFlightPlan(_subPage); + _kln89->ClearFlightPlan(_subPage); CrsrPressed(); } else if(_delWp) { int pos = _uLinePos - 4 + _fplPos; @@ -750,7 +750,7 @@ void KLN89FplPage::EntPressed() { } } else { // Use - _parent->ClearFlightPlan(0); + _kln89->ClearFlightPlan(0); for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) { GPSWaypoint* wp = new GPSWaypoint; *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]); @@ -759,13 +759,13 @@ void KLN89FplPage::EntPressed() { _kln89->OrientateToActiveFlightPlan(); _subPage = 0; } - _parent->CrsrPressed(); + _kln89->CrsrPressed(); } else if(_uLinePos == 2) { if(_kln89->_flightPlans[_subPage]->IsEmpty()) { // ERROR !!! } else { // Use Invert - _parent->ClearFlightPlan(0); + _kln89->ClearFlightPlan(0); for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) { GPSWaypoint* wp = new GPSWaypoint; *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]); @@ -774,7 +774,7 @@ void KLN89FplPage::EntPressed() { } _kln89->OrientateToActiveFlightPlan(); } - _parent->CrsrPressed(); + _kln89->CrsrPressed(); _subPage = 0; } } diff --git a/src/Instrumentation/KLN89/kln89_page_nav.cxx b/src/Instrumentation/KLN89/kln89_page_nav.cxx index 1a53659bc..0081d70a9 100644 --- a/src/Instrumentation/KLN89/kln89_page_nav.cxx +++ b/src/Instrumentation/KLN89/kln89_page_nav.cxx @@ -41,15 +41,15 @@ KLN89NavPage::KLN89NavPage(KLN89* parent) _menuPos = 0; _suspendAVS = false; _scanWpSet = false; - _scanWpIndex = -1; + _scanWpIndex = -1; } KLN89NavPage::~KLN89NavPage() { } void KLN89NavPage::Update(double dt) { - GPSFlightPlan* fp = ((KLN89*)_parent)->_activeFP; - GPSWaypoint* awp = _parent->GetActiveWaypoint(); + GPSFlightPlan* fp = _kln89->_activeFP; + GPSWaypoint* awp = _kln89->GetActiveWaypoint(); // Scan-pull out on nav4 page switches off the cursor if(3 == _subPage && fgGetBool("/instrumentation/kln89/scan-pull")) { _kln89->_mode = KLN89_MODE_DISP; } bool crsr = (_kln89->_mode == KLN89_MODE_CRSR); diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index a20189cd9..af232d70b 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -26,7 +26,6 @@ #include "dclgps.hxx" #include -#include #include #include @@ -39,85 +38,6 @@ using namespace std; -// Command callbacks for FlightGear - -static bool do_kln89_msg_pressed(const SGPropertyNode* arg) { - //cout << "do_kln89_msg_pressed called!\n"; - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->MsgPressed(); - return(true); -} - -static bool do_kln89_obs_pressed(const SGPropertyNode* arg) { - //cout << "do_kln89_obs_pressed called!\n"; - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->OBSPressed(); - return(true); -} - -static bool do_kln89_alt_pressed(const SGPropertyNode* arg) { - //cout << "do_kln89_alt_pressed called!\n"; - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->AltPressed(); - return(true); -} - -static bool do_kln89_nrst_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->NrstPressed(); - return(true); -} - -static bool do_kln89_dto_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->DtoPressed(); - return(true); -} - -static bool do_kln89_clr_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->ClrPressed(); - return(true); -} - -static bool do_kln89_ent_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->EntPressed(); - return(true); -} - -static bool do_kln89_crsr_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->CrsrPressed(); - return(true); -} - -static bool do_kln89_knob1left1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob1Left1(); - return(true); -} - -static bool do_kln89_knob1right1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob1Right1(); - return(true); -} - -static bool do_kln89_knob2left1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob2Left1(); - return(true); -} - -static bool do_kln89_knob2right1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob2Right1(); - return(true); -} - -// End command callbacks - GPSWaypoint::GPSWaypoint() { appType = GPS_APP_NONE; } @@ -222,58 +142,12 @@ ClockTime::ClockTime(int hr, int min) { ClockTime::~ClockTime() { } -GPSPage::GPSPage(DCLGPS* parent) { - _parent = parent; - _subPage = 0; -} - -GPSPage::~GPSPage() { -} - -void GPSPage::Update(double dt) {} - -void GPSPage::Knob1Left1() {} -void GPSPage::Knob1Right1() {} - -void GPSPage::Knob2Left1() { - _parent->_activePage->LooseFocus(); - _subPage--; - if(_subPage < 0) _subPage = _nSubPages - 1; -} - -void GPSPage::Knob2Right1() { - _parent->_activePage->LooseFocus(); - _subPage++; - if(_subPage >= _nSubPages) _subPage = 0; -} - -void GPSPage::CrsrPressed() {} -void GPSPage::EntPressed() {} -void GPSPage::ClrPressed() {} -void GPSPage::DtoPressed() {} -void GPSPage::NrstPressed() {} -void GPSPage::AltPressed() {} -void GPSPage::OBSPressed() {} -void GPSPage::MsgPressed() {} - -string GPSPage::GPSitoa(int n) { - char buf[6]; - snprintf(buf, 6, "%i", n); - string s = buf; - return(s); -} - -void GPSPage::CleanUp() {} -void GPSPage::LooseFocus() {} -void GPSPage::SetId(const string& s) {} - // ------------------------------------------------------------------------------------- // DCLGPS::DCLGPS(RenderArea2D* instrument) { _instrument = instrument; _nFields = 1; _maxFields = 2; - _pages.clear(); // Units - lets default to US units - FG can set them to other units from config during startup if desired. _altUnits = GPS_ALT_UNITS_FT; @@ -361,18 +235,6 @@ void DCLGPS::draw(osg::State& state) { } void DCLGPS::init() { - globals->get_commands()->addCommand("kln89_msg_pressed", do_kln89_msg_pressed); - globals->get_commands()->addCommand("kln89_obs_pressed", do_kln89_obs_pressed); - globals->get_commands()->addCommand("kln89_alt_pressed", do_kln89_alt_pressed); - globals->get_commands()->addCommand("kln89_nrst_pressed", do_kln89_nrst_pressed); - globals->get_commands()->addCommand("kln89_dto_pressed", do_kln89_dto_pressed); - globals->get_commands()->addCommand("kln89_clr_pressed", do_kln89_clr_pressed); - globals->get_commands()->addCommand("kln89_ent_pressed", do_kln89_ent_pressed); - globals->get_commands()->addCommand("kln89_crsr_pressed", do_kln89_crsr_pressed); - globals->get_commands()->addCommand("kln89_knob1left1", do_kln89_knob1left1); - globals->get_commands()->addCommand("kln89_knob1right1", do_kln89_knob1right1); - globals->get_commands()->addCommand("kln89_knob2left1", do_kln89_knob2left1); - globals->get_commands()->addCommand("kln89_knob2right1", do_kln89_knob2right1); // Not sure if this should be here, but OK for now. CreateDefaultFlightPlans(); @@ -659,6 +521,15 @@ void DCLGPS::update(double dt) { } } +GPSWaypoint* DCLGPS::GetActiveWaypoint() { + return &_activeWaypoint; +} + +// Returns meters +float DCLGPS::GetDistToActiveWaypoint() { + return _dist2Act; +} + // I don't yet fully understand all the gotchas about where to source time from. // This function sets the initial timer before the clock exports properties // and the one below uses the clock to be consistent with the rest of the code. @@ -709,18 +580,7 @@ void DCLGPS::DtoCancel() { _dto = false; } -void DCLGPS::Knob1Left1() {} -void DCLGPS::Knob1Right1() {} -void DCLGPS::Knob2Left1() {} -void DCLGPS::Knob2Right1() {} -void DCLGPS::CrsrPressed() { _activePage->CrsrPressed(); } -void DCLGPS::EntPressed() { _activePage->EntPressed(); } -void DCLGPS::ClrPressed() { _activePage->ClrPressed(); } -void DCLGPS::DtoPressed() {} -void DCLGPS::NrstPressed() {} -void DCLGPS::AltPressed() {} - -void DCLGPS::OBSPressed() { +void DCLGPS::ToggleOBSMode() { _obsMode = !_obsMode; if(_obsMode) { if(!_activeWaypoint.id.empty()) { @@ -742,8 +602,6 @@ void DCLGPS::SetOBSFromWaypoint() { _fromWaypoint.id = "OBSWP"; } -void DCLGPS::MsgPressed() {} - void DCLGPS::CDIFSDIncrease() { if(_currentCdiScaleIndex == 0) { _currentCdiScaleIndex = _cdiScales.size() - 1; diff --git a/src/Instrumentation/dclgps.hxx b/src/Instrumentation/dclgps.hxx index a7b6e0568..2f0d0f6e3 100644 --- a/src/Instrumentation/dclgps.hxx +++ b/src/Instrumentation/dclgps.hxx @@ -186,67 +186,9 @@ private: // ------------------------------------------------------------------------------ -class DCLGPS; - -class GPSPage { - -public: - GPSPage(DCLGPS* parent); - virtual ~GPSPage() = 0; - virtual void Update(double dt); - virtual void Knob1Left1(); - virtual void Knob1Right1(); - virtual void Knob2Left1(); - virtual void Knob2Right1(); - virtual void CrsrPressed(); - virtual void EntPressed(); - virtual void ClrPressed(); - virtual void DtoPressed(); - virtual void NrstPressed(); - virtual void AltPressed(); - virtual void OBSPressed(); - virtual void MsgPressed(); - - // Sometimes a page needs to maintain state for some return paths, - // but change it for others. The CleanUp function can be used for - // changing state for non-ENT return paths in conjunction with - // GPS::_cleanUpPage - virtual void CleanUp(); - - // The LooseFocus function is called when a page or subpage looses focus - // and allows pages to clean up state that is maintained whilst focus is - // retained, but lost on return. - virtual void LooseFocus(); - - // Allows pages that display info for a given ID to have it set/get if they implement these functions. - virtual void SetId(const string& s); - virtual const string& GetId()=0; - - inline int GetSubPage() { return(_subPage); } - - inline int GetNSubPages() { return(_nSubPages); } - - inline const string& GetName() { return(_name); } - -protected: - DCLGPS* _parent; - string _name; // eg. "APT", "NAV" etc - int _nSubPages; - // _subpage is zero based - int _subPage; // The subpage gets remembered when other pages are displayed - string GPSitoa(int n); -}; - -/*-----------------------------------------------------------------------*/ - -typedef vector gps_page_list_type; -typedef gps_page_list_type::iterator gps_page_list_itr; - // TODO - merge generic GPS functions instead and split out KLN specific stuff. class DCLGPS : public SGSubsystem { - friend class GPSPage; - public: DCLGPS(RenderArea2D* instrument); virtual ~DCLGPS() = 0; @@ -266,18 +208,7 @@ public: // Render a char at a given position as above virtual void DrawChar(char c, int field, int px, int py, bool bold = false); - virtual void Knob1Right1(); - virtual void Knob1Left1(); - virtual void Knob2Right1(); - virtual void Knob2Left1(); - virtual void CrsrPressed(); - virtual void EntPressed(); - virtual void ClrPressed(); - virtual void DtoPressed(); - virtual void NrstPressed(); - virtual void AltPressed(); - virtual void OBSPressed(); - virtual void MsgPressed(); + virtual void ToggleOBSMode(); // Set the number of fields inline void SetNumFields(int n) { _nFields = (n > _maxFields ? _maxFields : (n < 1 ? 1 : n)); } @@ -309,7 +240,7 @@ public: void SetOBSFromWaypoint(); - inline GPSWaypoint* GetActiveWaypoint() { return &_activeWaypoint; } + GPSWaypoint* GetActiveWaypoint(); // Get the (zero-based) position of the active waypoint in the active flightplan // Returns -1 if no active waypoint. int GetActiveWaypointIndex(); @@ -317,7 +248,7 @@ public: int GetWaypointIndex(const string& id); // Returns meters - inline float GetDistToActiveWaypoint() { return _dist2Act; } + float GetDistToActiveWaypoint(); // Returns degrees (magnetic) float GetHeadingToActiveWaypoint(); // Returns degrees (magnetic) @@ -383,14 +314,6 @@ protected: // 2D rendering area RenderArea2D* _instrument; - // The actual pages - gps_page_list_type _pages; - - // The currently active page - GPSPage* _activePage; - // And a facility to save the immediately preceeding active page - GPSPage* _lastActivePage; - // Units GPSSpeedUnits _velUnits; GPSDistanceUnits _distUnits; diff --git a/src/Instrumentation/navradio.cxx b/src/Instrumentation/navradio.cxx index ee217d6c9..782786fd0 100644 --- a/src/Instrumentation/navradio.cxx +++ b/src/Instrumentation/navradio.cxx @@ -150,6 +150,7 @@ FGNavRadio::FGNavRadio(SGPropertyNode *node) : last_x(0.0), last_loc_dist(0.0), last_xtrack_error(0.0), + xrate_ms(0.0), _localizerWidth(5.0), _name(node->getStringValue("name", "nav")), _num(node->getIntValue("number", 0)), @@ -740,7 +741,8 @@ void FGNavRadio::updateCDI(double dt) ////////////////////////////////////////////////////////// double t = 0.0; if ( inrange && cdi_serviceable ) { - double xrate_ms = (last_xtrack_error - _cdiCrossTrackErrorM) / dt; + double cur_rate = (last_xtrack_error - _cdiCrossTrackErrorM) / dt; + xrate_ms = 0.99 * xrate_ms + 0.01 * cur_rate; if ( fabs(xrate_ms) > 0.00001 ) { t = _cdiCrossTrackErrorM / xrate_ms; } else { diff --git a/src/Instrumentation/navradio.hxx b/src/Instrumentation/navradio.hxx index 3ee3e4155..234938675 100644 --- a/src/Instrumentation/navradio.hxx +++ b/src/Instrumentation/navradio.hxx @@ -136,6 +136,7 @@ class FGNavRadio : public SGSubsystem double last_x; double last_loc_dist; double last_xtrack_error; + double xrate_ms; double _localizerWidth; // cached localizer width in degrees string _name;