]> git.mxchange.org Git - flightgear.git/commitdiff
Add RS, JK, D and T flip flops as components
authorTorsten Dreyer <Torsten@t3r.de>
Mon, 24 May 2010 09:57:55 +0000 (11:57 +0200)
committerTorsten Dreyer <Torsten@t3r.de>
Mon, 24 May 2010 09:57:55 +0000 (11:57 +0200)
Flip flops are useful items for data latches and can be used to implement
pushbuttons, glideslope locks etc.
Check http://en.wikipedia.org/wiki/Flip-flop_(electronics)
and http://wiki.flightgear.org/index.php/Autopilot_Configuration_Reference
for details

src/Autopilot/xmlauto.cxx
src/Autopilot/xmlauto.hxx

index fe51f37b126023009edb8514ab1685e344e27b15..56df5cf86ae309beb5934c0948dffc14fe469994 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <iostream>
 
+#include <simgear/misc/strutils.hxx>
 #include <simgear/structure/exception.hxx>
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/sg_inlines.h>
@@ -893,6 +894,237 @@ void FGXMLAutoLogic::update(double dt)
     set_output_value( i );
 }
 
+class FGXMLAutoRSFlipFlop : public FGXMLAutoFlipFlop {
+public:
+  FGXMLAutoRSFlipFlop( SGPropertyNode * node ) :
+    FGXMLAutoFlipFlop( node ) {}
+
+  void updateState( double dt ) {
+
+    if( sInput == NULL ) {
+        if ( debug ) cout << "No set (S) input for " << get_name() << endl;
+        return;
+    }
+
+    if( rInput == NULL ) {
+        if ( debug ) cout << "No reset (R) input for " << get_name() << endl;
+        return;
+    }
+
+    bool s = sInput->test();
+    bool r = rInput->test();
+
+    // s == false && q == false: no change, keep state
+    if( s || r ) {
+      bool q = false;
+      if( s ) q = true; // set
+      if( r ) q = false; // reset
+      // s && q: race condition. we let r win
+      if( inverted ) q = !q;
+
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << " s=" << s
+        << ",r=" << r
+        << ",q=" << q << endl;
+      set_output_value( q );
+    } else {
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << " s=" << s
+        << ",r=" << r
+        << ",q=unchanged" << endl;
+    }
+  }
+};
+
+class FGXMLAutoJKFlipFlop : public FGXMLAutoFlipFlop {
+private: 
+  bool clock;
+public:
+  FGXMLAutoJKFlipFlop( SGPropertyNode * node ) :
+    FGXMLAutoFlipFlop( node ), 
+    clock(false) {}
+
+  void updateState( double dt ) {
+
+    if( jInput == NULL ) {
+        if ( debug ) cout << "No set (j) input for " << get_name() << endl;
+        return;
+    }
+
+    if( kInput == NULL ) {
+        if ( debug ) cout << "No reset (k) input for " << get_name() << endl;
+        return;
+    }
+
+    bool j = jInput->test();
+    bool k = kInput->test();
+    /*
+      if the user provided a clock input, use it. 
+      Otherwise use framerate as clock
+      This JK operates on the raising edge. 
+    */
+    bool c = clockInput ? clockInput->test() : false;
+    bool raisingEdge = clockInput ? (c && !clock) : true;
+    clock = c;
+
+    if( !raisingEdge ) return;
+    
+    bool q = get_bool_output_value();
+    // j == false && k == false: no change, keep state
+    if( (j || k) ) {
+      if( j && k ) {
+        q = !q; // toggle
+      } else {
+        if( j ) q = true; // set
+        if( k ) q = false; // reset
+      }
+      if( inverted ) q = !q;
+
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << " j=" << j
+        << ",k=" << k
+        << ",q=" << q << endl;
+      set_output_value( q );
+    } else {
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << " j=" << j
+        << ",k=" << k
+        << ",q=unchanged" << endl;
+    }
+  }
+};
+
+class FGXMLAutoDFlipFlop : public FGXMLAutoFlipFlop {
+private: 
+  bool clock;
+public:
+  FGXMLAutoDFlipFlop( SGPropertyNode * node ) :
+    FGXMLAutoFlipFlop( node ), 
+    clock(false) {}
+
+  void updateState( double dt ) {
+
+    if( clockInput == NULL ) {
+        if ( debug ) cout << "No (clock) input for " << get_name() << endl;
+        return;
+    }
+
+    if( dInput == NULL ) {
+        if ( debug ) cout << "No (D) input for " << get_name() << endl;
+        return;
+    }
+
+    bool d = dInput->test();
+
+    // check the clock - raising edge
+    bool c = clockInput->test();
+    bool raisingEdge = c && !clock;
+    clock = c;
+
+    if( raisingEdge ) {
+      bool q = d;
+      if( inverted ) q = !q;
+
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << " d=" << d
+        << ",q=" << q << endl;
+      set_output_value( q );
+    } else {
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << " d=" << d
+        << ",q=unchanged" << endl;
+    }
+  }
+};
+
+class FGXMLAutoTFlipFlop : public FGXMLAutoFlipFlop {
+private: 
+  bool clock;
+public:
+  FGXMLAutoTFlipFlop( SGPropertyNode * node ) :
+    FGXMLAutoFlipFlop( node ), 
+    clock(false) {}
+
+  void updateState( double dt ) {
+
+    if( clockInput == NULL ) {
+        if ( debug ) cout << "No (clock) input for " << get_name() << endl;
+        return;
+    }
+
+    // check the clock - raising edge
+    bool c = clockInput->test();
+    bool raisingEdge = c && !clock;
+    clock = c;
+
+    if( raisingEdge ) {
+      bool q = !get_bool_output_value(); // toggle
+      if( inverted ) q = !q; // doesnt really make sense for a T-FF
+
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << ",q=" << q << endl;
+      set_output_value( q );
+    } else {
+      if ( debug ) cout << "Updating " << get_name() << ":" 
+        << ",q=unchanged" << endl;
+    }
+  }
+};
+
+FGXMLAutoFlipFlop::FGXMLAutoFlipFlop(SGPropertyNode * node ) :
+    FGXMLAutoComponent(),
+    inverted(false)
+{
+    parseNode(node);
+}
+
+bool FGXMLAutoFlipFlop::parseNodeHook(const std::string& aName, SGPropertyNode* aNode)
+{
+    if (aName == "set"||aName == "S") {
+        sInput = sgReadCondition( fgGetNode("/"), aNode );
+    } else if (aName == "reset" || aName == "R" ) {
+        rInput = sgReadCondition( fgGetNode("/"), aNode );
+    } else if (aName == "J") {
+        jInput = sgReadCondition( fgGetNode("/"), aNode );
+    } else if (aName == "K") {
+        kInput = sgReadCondition( fgGetNode("/"), aNode );
+    } else if (aName == "T") {
+        tInput = sgReadCondition( fgGetNode("/"), aNode );
+    } else if (aName == "D") {
+        dInput = sgReadCondition( fgGetNode("/"), aNode );
+    } else if (aName == "clock") {
+        clockInput = sgReadCondition( fgGetNode("/"), aNode );
+    } else if (aName == "inverted") {
+        inverted = aNode->getBoolValue();
+    } else if (aName == "type") {
+        // ignore element type, evaluated by loader
+    } else {
+        return false;
+    }
+  
+    return true;
+}
+
+void FGXMLAutoFlipFlop::update(double dt)
+{
+    if ( isPropertyEnabled() ) {
+        if ( !enabled ) {
+            // we have just been enabled
+            // initialize to a bool property
+            set_output_value( get_bool_output_value() );
+        }
+        enabled = true;
+    } else {
+        enabled = false;
+        do_feedback();
+    }
+
+    if ( !enabled || dt < SGLimitsd::min() ) 
+        return;
+
+    updateState( dt );
+}
+
 
 FGXMLAutopilotGroup::FGXMLAutopilotGroup() :
   SGSubsystemGroup()
@@ -1113,6 +1345,21 @@ bool FGXMLAutopilot::build( SGPropertyNode_ptr config_props ) {
             components.push_back( new FGDigitalFilter( node ) );
         } else if ( name == "logic" ) {
             components.push_back( new FGXMLAutoLogic( node ) );
+        } else if ( name == "flipflop" ) {
+            FGXMLAutoFlipFlop * flipFlop = NULL;
+            SGPropertyNode_ptr typeNode = node->getNode( "type" );            
+            string val;
+            if( typeNode != NULL ) val = typeNode->getStringValue();
+            val = simgear::strutils::strip(val);
+            if( val == "RS" || val =="SR" ) flipFlop      = new FGXMLAutoRSFlipFlop( node );
+            else if( val == "JK" ) flipFlop = new FGXMLAutoJKFlipFlop( node );
+            else if( val == "T" ) flipFlop  = new FGXMLAutoTFlipFlop( node );
+            else if( val == "D" ) flipFlop  = new FGXMLAutoDFlipFlop( node );
+            if( flipFlop == NULL ) {
+              SG_LOG(SG_AUTOPILOT, SG_ALERT, "can't create flipflop of type: " << val);
+              return false;
+            }
+            components.push_back( flipFlop );
         } else {
             SG_LOG( SG_AUTOPILOT, SG_WARN, "Unknown top level autopilot section: " << name );
 //            return false;
index a29d49e236b827f86030bc01e1cb200d694ccced..ccc17ee5667675dde3c26733563d7b95fe989444 100644 (file)
@@ -222,6 +222,10 @@ public:
       return output_list.size() == 0 ? 0.0 : clamp(output_list[0]->getDoubleValue());
     }
 
+    inline bool get_bool_output_value() {
+      return output_list.size() == 0 ? false : output_list[0]->getBoolValue();
+    }
+
     /* 
        Returns true if the enable-condition is true.
 
@@ -381,9 +385,9 @@ private:
 
     std::deque <double> output;
     std::deque <double> input;
-    enum filterTypes { exponential, doubleExponential, movingAverage,
+    enum FilterTypes { exponential, doubleExponential, movingAverage,
                        noiseSpike, gain, reciprocal, differential, none };
-    filterTypes filterType;
+    FilterTypes filterType;
 
 protected:
   bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
@@ -411,6 +415,28 @@ public:
     void update(double dt);
 };
 
+class FGXMLAutoFlipFlop : public FGXMLAutoComponent
+{
+private:
+protected:
+    SGSharedPtr<SGCondition> sInput;
+    SGSharedPtr<SGCondition> rInput;
+    SGSharedPtr<SGCondition> clockInput;
+    SGSharedPtr<SGCondition> jInput;
+    SGSharedPtr<SGCondition> kInput;
+    SGSharedPtr<SGCondition> tInput;
+    SGSharedPtr<SGCondition> dInput;
+    bool inverted;
+    FGXMLAutoFlipFlop( SGPropertyNode * node );
+    bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
+
+    void update( double dt );
+    virtual void updateState( double dt ) = 0;
+
+public:
+    ~FGXMLAutoFlipFlop() {};
+};
+
 /**
  * Model an autopilot system.
  *