Add RS, JK, D and T flip flops as components
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
This commit is contained in:
parent
a060fe3acf
commit
9e35d18f2e
2 changed files with 275 additions and 2 deletions
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/sg_inlines.h>
|
#include <simgear/sg_inlines.h>
|
||||||
|
@ -893,6 +894,237 @@ void FGXMLAutoLogic::update(double dt)
|
||||||
set_output_value( i );
|
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() :
|
FGXMLAutopilotGroup::FGXMLAutopilotGroup() :
|
||||||
SGSubsystemGroup()
|
SGSubsystemGroup()
|
||||||
|
@ -1113,6 +1345,21 @@ bool FGXMLAutopilot::build( SGPropertyNode_ptr config_props ) {
|
||||||
components.push_back( new FGDigitalFilter( node ) );
|
components.push_back( new FGDigitalFilter( node ) );
|
||||||
} else if ( name == "logic" ) {
|
} else if ( name == "logic" ) {
|
||||||
components.push_back( new FGXMLAutoLogic( node ) );
|
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 {
|
} else {
|
||||||
SG_LOG( SG_AUTOPILOT, SG_WARN, "Unknown top level autopilot section: " << name );
|
SG_LOG( SG_AUTOPILOT, SG_WARN, "Unknown top level autopilot section: " << name );
|
||||||
// return false;
|
// return false;
|
||||||
|
|
|
@ -222,6 +222,10 @@ public:
|
||||||
return output_list.size() == 0 ? 0.0 : clamp(output_list[0]->getDoubleValue());
|
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.
|
Returns true if the enable-condition is true.
|
||||||
|
|
||||||
|
@ -381,9 +385,9 @@ private:
|
||||||
|
|
||||||
std::deque <double> output;
|
std::deque <double> output;
|
||||||
std::deque <double> input;
|
std::deque <double> input;
|
||||||
enum filterTypes { exponential, doubleExponential, movingAverage,
|
enum FilterTypes { exponential, doubleExponential, movingAverage,
|
||||||
noiseSpike, gain, reciprocal, differential, none };
|
noiseSpike, gain, reciprocal, differential, none };
|
||||||
filterTypes filterType;
|
FilterTypes filterType;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
|
bool parseNodeHook(const std::string& aName, SGPropertyNode* aNode);
|
||||||
|
@ -411,6 +415,28 @@ public:
|
||||||
void update(double dt);
|
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.
|
* Model an autopilot system.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Reference in a new issue