#include "inputvalue.hxx"
#include <Main/fg_props.hxx>
-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.
+ *
+ * <table>
+ * <tr>
+ * <td colspan="3">Logictable</td>
+ * </tr>
+ * <tr>
+ * <td>S</td><td>R</td><td>Q</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>false</td><td>unchanged</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>true</td><td>false</td>
+ * </tr>
+ * <tr>
+ * <td>true</td><td>false</td><td>true</td>
+ * </tr>
+ * <tr>
+ * <td>true</td><td>true</td><td>false</td>
+ * </tr>
+ * </table>
+ */
class RSFlipFlopImplementation : public FlipFlopImplementation {
protected:
bool _rIsDominant;
virtual bool getState( double dt, DigitalComponent::InputMap input, bool & q );
};
+/**
+ * @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.
+ *
+ * <table>
+ * <tr>
+ * <td colspan="3">Logictable</td>
+ * </tr>
+ * <tr>
+ * <td>S</td><td>R</td><td>Q</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>false</td><td>unchanged</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>true</td><td>false</td>
+ * </tr>
+ * <tr>
+ * <td>true</td><td>false</td><td>true</td>
+ * </tr>
+ * <tr>
+ * <td>true</td><td>true</td><td>true</td>
+ * </tr>
+ * </table>
+ */
class SRFlipFlopImplementation : public RSFlipFlopImplementation {
public:
SRFlipFlopImplementation() : RSFlipFlopImplementation( false ) {}
};
+/**
+ * @brief Base class for clocked flip flop implementation
+ *
+ * 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. 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 {
-protected:
+private:
+ /**
+ * @brief the previous state of the clock input
+ */
bool _clock;
+protected:
+
+ /**
+ * @brief pure virtual function to be implemented from the implementing class, gets called
+ * from the update method if the raising edge of the clock input was detected.
+ * @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 ) = 0;
public:
+
+ /**
+ * @brief constructor for a ClockedFlipFlopImplementation
+ * @param rIsDominant boolean flag to signal if RESET shall be dominant (true) or SET shall be dominant (false)
+ */
ClockedFlipFlopImplementation( bool rIsDominant = true ) : RSFlipFlopImplementation( rIsDominant ), _clock(false) {}
+
+ /**
+ * @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
+ * @return true if the state has changed, false otherwise
+ */
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.
+ *
+ * <table>
+ * <tr>
+ * <td colspan="7">Logictable</td>
+ * </tr>
+ * <tr>
+ * <td>S</td><td>R</td><td>J</td><td>K</td><td>clock</td><td>Q (previous)</td><td>Q</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>false</td><td>false</td><td>false</td><td>any</td><td>any</td><td>unchanged</td>
+ * </tr>
+ * <tr>
+ * <td>true</td><td>false</td><td>any</td><td>any</td><td>any</td><td>any</td><td>true</td>
+ * </tr>
+ * <tr>
+ * <td>any</td><td>true</td><td>any</td><td>any</td><td>any</td><td>any</td><td>false</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>false</td><td>true</td><td>false</td><td>^</td><td>any</td><td>true</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>false</td><td>false</td><td>true</td><td>^</td><td>any</td><td>false</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>false</td><td>true</td><td>true</td><td>^</td><td>false</td><td>true</td>
+ * </tr>
+ * <tr>
+ * <td>false</td><td>false</td><td>true</td><td>true</td><td>^</td><td>true</td><td>false</td>
+ * </tr>
+ * </table>
+ */
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 );
InputValueList _time;
double _t;
public:
+ /**
+ * @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 ) {}
+ /**
+ * @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 );
};
+} // namespace
+
+using namespace FGXMLAutopilot;
+
bool MonoFlopImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
{
if( JKFlipFlopImplementation::configure( nodeName, configNode ) )
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 );
}
q0 = q = get_output();
- if( _implementation->getState( dt, _input, q ) ) {
+ if( _implementation->getState( dt, _input, q ) && q0 != q ) {
set_output( q );
if(_debug) {