X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAutopilot%2Fflipflop.cxx;h=484f89d0588b67dbfdede9af479bf8bde0db003b;hb=ec2baa1a418b2ba4e45f745ee76d88801feb7e72;hp=7b57d95ce72dcd7169341825c4b6237d6679519e;hpb=47c956b51673ff979707bbfa999bd20fd4540e8c;p=flightgear.git diff --git a/src/Autopilot/flipflop.cxx b/src/Autopilot/flipflop.cxx index 7b57d95ce..484f89d05 100644 --- a/src/Autopilot/flipflop.cxx +++ b/src/Autopilot/flipflop.cxx @@ -24,11 +24,22 @@ #include "inputvalue.hxx" #include
-using namespace FGXMLAutopilot; +using std::map; +using std::string; +using std::endl; +using std::cout; + +namespace FGXMLAutopilot { /** * @brief Flip flop implementation for a RS flip flop with dominant RESET * + * RS (reset-set) flip flops act as a fundamental latch. It has two input lines, + * S (set) and R (reset). Activating the set input sets the output while activating + * the reset input resets the output. If both inputs are activated, the output + * is deactivated, too. This is why the RESET line is called dominant. Use a + * SRFlipFlopImplementation for a dominant SET line. + * * * * @@ -61,6 +72,12 @@ public: /** * @brief Flip flop implementation for a RS flip flop with dominant SET * + * SR (set-reset) flip flops act as a fundamental latch. It has two input lines, + * S (set) and R (reset). Activating the set input sets the output while activating + * the reset input resets the output. If both inputs are activated, the output + * is activated, too. This is why the SET line is called dominant. Use a + * RSFlipFlopImplementation for a dominant RESET line. + * *
Logictable
* * @@ -92,7 +109,11 @@ public: * * A clocked flip flop computes it's output on the raising edge (false/true transition) * of the clock input. If such a transition is detected, the onRaisingEdge method is called - * by this implementation + * by this implementation. All clocked flip flops inherit from the RS flip flop and may + * be set or reset by the respective set/reset lines. Note that the RS implementation + * ignores the clock, The output is set immediately, regardless of the state of the clock + * input. The "clock" input is mandatory for clocked flip flops. + * */ class ClockedFlipFlopImplementation : public RSFlipFlopImplementation { private: @@ -119,7 +140,8 @@ public: ClockedFlipFlopImplementation( bool rIsDominant = true ) : RSFlipFlopImplementation( rIsDominant ), _clock(false) {} /** - * @brief evaluates the output state from the input lines, basically waits for a raising edge and calls onRaisingEdge + * @brief evaluates the output state from the input lines. + * This method basically waits for a raising edge and calls onRaisingEdge * @param dt the elapsed time in seconds from since the last call * @param input a map of named input lines * @param q a reference to a boolean variable to receive the output state @@ -128,47 +150,156 @@ public: virtual bool getState( double dt, DigitalComponent::InputMap input, bool & q ); }; +/** + * @brief Implements a JK flip flop as a clocked flip flop + * + * The JK flip flop has five input lines: R, S, clock, J and K. The R and S lines work as described + * in the RS flip flop. Setting the J line to true sets the output to true on the next raising + * edge of the clock line. Setting the K line to true sets the output to false on the next raising + * edge of the clock line. If both, J and K are true, the output is toggled at with every raising + * edge of the clock line. + * + * Undefined inputs default to false. + * + *
Logictable
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Logictable
SRJKclockQ (previous)Q
falsefalsefalsefalseanyanyunchanged
truefalseanyanyanyanytrue
anytrueanyanyanyanyfalse
falsefalsetruefalse^anytrue
falsefalsefalsetrue^anyfalse
falsefalsetruetrue^falsetrue
falsefalsetruetrue^truefalse
+ */ class JKFlipFlopImplementation : public ClockedFlipFlopImplementation { public: + /** + * @brief constructor for a JKFlipFlopImplementation + * @param rIsDominant boolean flag to signal if RESET shall be dominant (true) or SET shall be dominant (false) + */ JKFlipFlopImplementation( bool rIsDominant = true ) : ClockedFlipFlopImplementation ( rIsDominant ) {} + + /** + * @brief compute the output state according to the logic table on the raising edge of the clock + * @param input a map of named input lines + * @param q a reference to a boolean variable to receive the output state + * @return true if the state has changed, false otherwise + */ virtual bool onRaisingEdge( DigitalComponent::InputMap input, bool & q ); }; +/** + * @brief Implements a D (delay) flip flop. + * + */ class DFlipFlopImplementation : public ClockedFlipFlopImplementation { public: + /** + * @brief constructor for a DFlipFlopImplementation + * @param rIsDominant boolean flag to signal if RESET shall be dominant (true) or SET shall be dominant (false) + */ DFlipFlopImplementation( bool rIsDominant = true ) : ClockedFlipFlopImplementation ( rIsDominant ) {} + + /** + * @brief compute the output state according to the logic table on the raising edge of the clock + * @param input a map of named input lines + * @param q a reference to a boolean variable to receive the output state + * @return true if the state has changed, false otherwise + */ virtual bool onRaisingEdge( DigitalComponent::InputMap input, bool & q ) { q = input.get_value("D"); return true; } }; +/** + * @brief Implements a T (toggle) flip flop. + * + */ class TFlipFlopImplementation : public ClockedFlipFlopImplementation { public: + /** + * @brief constructor for a TFlipFlopImplementation + * @param rIsDominant boolean flag to signal if RESET shall be dominant (true) or SET shall be dominant (false) + */ TFlipFlopImplementation( bool rIsDominant = true ) : ClockedFlipFlopImplementation ( rIsDominant ) {} + + /** + * @brief compute the output state according to the logic table on the raising edge of the clock + * @param input a map of named input lines + * @param q a reference to a boolean variable to receive the output state + * @return true if the state has changed, false otherwise + */ virtual bool onRaisingEdge( DigitalComponent::InputMap input, bool & q ) { q = !q; return true; } }; +/** + * @brief Implements a monostable flip flop + * + * The stable output state is false. + * + */ class MonoFlopImplementation : public JKFlipFlopImplementation { protected: - virtual bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode ); + virtual bool configure( SGPropertyNode& cfg_node, + const std::string& cfg_name, + SGPropertyNode& prop_root ); InputValueList _time; double _t; public: - MonoFlopImplementation( bool rIsDominant = true ) : JKFlipFlopImplementation( rIsDominant ) {} + /** + * @brief constructor for a MonoFlopImplementation + * @param rIsDominant boolean flag to signal if RESET shall be dominant (true) or SET shall be dominant (false) + */ + MonoFlopImplementation( bool rIsDominant = true ) : JKFlipFlopImplementation( rIsDominant ), _t(0.0) {} + /** + * @brief evaluates the output state from the input lines and returns to the stable state + * after expiry of the internal timer + * @param dt the elapsed time in seconds from since the last call + * @param input a map of named input lines + * @param q a reference to a boolean variable to receive the output state + * @return true if the state has changed, false otherwise + */ virtual bool getState( double dt, DigitalComponent::InputMap input, bool & q ); }; -bool MonoFlopImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode ) +} // namespace + +using namespace FGXMLAutopilot; + +//------------------------------------------------------------------------------ +bool MonoFlopImplementation::configure( SGPropertyNode& cfg_node, + const std::string& cfg_name, + SGPropertyNode& prop_root ) { - if( JKFlipFlopImplementation::configure( nodeName, configNode ) ) + if( JKFlipFlopImplementation::configure(cfg_node, cfg_name, prop_root) ) return true; - if (nodeName == "time") { - _time.push_back( new InputValue( configNode ) ); + if (cfg_name == "time") { + _time.push_back( new InputValue(prop_root, cfg_node) ); return true; } @@ -213,14 +344,15 @@ bool RSFlipFlopImplementation::getState( double dt, DigitalComponent::InputMap i bool ClockedFlipFlopImplementation::getState( double dt, DigitalComponent::InputMap input, bool & q ) { - if( RSFlipFlopImplementation::getState( dt, input, q ) ) - return true; - bool c = input.get_value("clock"); bool raisingEdge = c && !_clock; _clock = c; + if( RSFlipFlopImplementation::getState( dt, input, q ) ) + return true; + + if( !raisingEdge ) return false; //signal no change return onRaisingEdge( input, q ); } @@ -244,18 +376,18 @@ bool JKFlipFlopImplementation::onRaisingEdge( DigitalComponent::InputMap input, return false; // signal no change } -bool FlipFlopImplementation::configure( SGPropertyNode_ptr configNode ) +//------------------------------------------------------------------------------ +bool FlipFlopImplementation::configure( SGPropertyNode& prop_root, + SGPropertyNode& cfg ) { - for (int i = 0; i < configNode->nChildren(); ++i ) { - SGPropertyNode_ptr prop; - - SGPropertyNode_ptr child = configNode->getChild(i); + for( int i = 0; i < cfg.nChildren(); ++i ) + { + SGPropertyNode_ptr child = cfg.getChild(i); string cname(child->getName()); - if( configure( cname, child ) ) + if( configure(*child, cname, prop_root) ) continue; - - } // for configNode->nChildren() + } return true; } @@ -263,7 +395,10 @@ bool FlipFlopImplementation::configure( SGPropertyNode_ptr configNode ) static map *> componentForge; -bool FlipFlop::configure( const std::string & nodeName, SGPropertyNode_ptr configNode ) +//------------------------------------------------------------------------------ +bool FlipFlop::configure( SGPropertyNode& cfg_node, + const std::string& cfg_name, + SGPropertyNode& prop_root ) { if( componentForge.empty() ) { componentForge["RS"] = new CreateAndConfigureFunctor(); @@ -274,46 +409,51 @@ bool FlipFlop::configure( const std::string & nodeName, SGPropertyNode_ptr confi componentForge["monostable"] = new CreateAndConfigureFunctor(); } - if( DigitalComponent::configure( nodeName, configNode ) ) + if( DigitalComponent::configure(cfg_node, cfg_name, prop_root) ) return true; - if( nodeName == "type" ) { - string type(configNode->getStringValue()); + if( cfg_name == "type" ) { + string type(cfg_node.getStringValue()); if( componentForge.count(type) == 0 ) { - SG_LOG( SG_AUTOPILOT, SG_BULK, "unhandled flip-flop type <" << type << ">" << endl ); + SG_LOG + ( + SG_AUTOPILOT, + SG_BULK, + "unhandled flip-flop type <" << type << ">" + ); return true; } - _implementation = (*componentForge[type])( configNode->getParent() ); + _implementation = (*componentForge[type])(prop_root, *cfg_node.getParent()); return true; } - if (nodeName == "set"||nodeName == "S") { - _input["S"] = sgReadCondition( fgGetNode("/"), configNode ); + if (cfg_name == "set"||cfg_name == "S") { + _input["S"] = sgReadCondition(&prop_root, &cfg_node); return true; } - if (nodeName == "reset" || nodeName == "R" ) { - _input["R"] = sgReadCondition( fgGetNode("/"), configNode ); + if (cfg_name == "reset" || cfg_name == "R" ) { + _input["R"] = sgReadCondition(&prop_root, &cfg_node); return true; } - if (nodeName == "J") { - _input["J"] = sgReadCondition( fgGetNode("/"), configNode ); + if (cfg_name == "J") { + _input["J"] = sgReadCondition(&prop_root, &cfg_node); return true; } - if (nodeName == "K") { - _input["K"] = sgReadCondition( fgGetNode("/"), configNode ); + if (cfg_name == "K") { + _input["K"] = sgReadCondition(&prop_root, &cfg_node); return true; } - if (nodeName == "D") { - _input["D"] = sgReadCondition( fgGetNode("/"), configNode ); + if (cfg_name == "D") { + _input["D"] = sgReadCondition(&prop_root, &cfg_node); return true; } - if (nodeName == "clock") { - _input["clock"] = sgReadCondition( fgGetNode("/"), configNode ); + if (cfg_name == "clock") { + _input["clock"] = sgReadCondition(&prop_root, &cfg_node); return true; } @@ -331,13 +471,13 @@ void FlipFlop::update( bool firstTime, double dt ) q0 = q = get_output(); - if( _implementation->getState( dt, _input, q ) ) { + if( _implementation->getState( dt, _input, q ) && q0 != q ) { set_output( q ); if(_debug) { cout << "updating flip-flop \"" << get_name() << "\"" << endl; cout << "prev. Output:" << q0 << endl; - for( InputMap::const_iterator it = _input.begin(); it != _input.end(); it++ ) + for( InputMap::const_iterator it = _input.begin(); it != _input.end(); ++it ) cout << "Input \"" << (*it).first << "\":" << (*it).second->test() << endl; cout << "new Output:" << q << endl; }