1 // flipflop.hxx - implementation of multiple flip flop types
3 // Written by Torsten Dreyer
5 // Copyright (C) 2010 Torsten Dreyer - Torsten (at) t3r (dot) de
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "flipflop.hxx"
23 #include "functor.hxx"
24 #include "inputvalue.hxx"
25 #include <Main/fg_props.hxx>
27 using namespace FGXMLAutopilot;
30 * @brief Flip flop implementation for a RS flip flop with dominant RESET
34 * <td colspan="3">Logictable</td>
37 * <td>S</td><td>R</td><td>Q</td>
40 * <td>false</td><td>false</td><td>unchanged</td>
43 * <td>false</td><td>true</td><td>false</td>
46 * <td>true</td><td>false</td><td>true</td>
49 * <td>true</td><td>true</td><td>false</td>
53 class RSFlipFlopImplementation : public FlipFlopImplementation {
57 RSFlipFlopImplementation( bool rIsDominant = true ) : _rIsDominant( rIsDominant ) {}
58 virtual bool getState( double dt, DigitalComponent::InputMap input, bool & q );
62 * @brief Flip flop implementation for a RS flip flop with dominant SET
66 * <td colspan="3">Logictable</td>
69 * <td>S</td><td>R</td><td>Q</td>
72 * <td>false</td><td>false</td><td>unchanged</td>
75 * <td>false</td><td>true</td><td>false</td>
78 * <td>true</td><td>false</td><td>true</td>
81 * <td>true</td><td>true</td><td>true</td>
85 class SRFlipFlopImplementation : public RSFlipFlopImplementation {
87 SRFlipFlopImplementation() : RSFlipFlopImplementation( false ) {}
91 * @brief Base class for clocked flip flop implementation
93 * A clocked flip flop computes it's output on the raising edge (false/true transition)
94 * of the clock input. If such a transition is detected, the onRaisingEdge method is called
95 * by this implementation
97 class ClockedFlipFlopImplementation : public RSFlipFlopImplementation {
100 * @brief the previous state of the clock input
106 * @brief pure virtual function to be implemented from the implementing class, gets called
107 * from the update method if the raising edge of the clock input was detected.
108 * @param input a map of named input lines
109 * @param q a reference to a boolean variable to receive the output state
110 * @return true if the state has changed, false otherwise
112 virtual bool onRaisingEdge( DigitalComponent::InputMap input, bool & q ) = 0;
116 * @brief constructor for a ClockedFlipFlopImplementation
117 * @param rIsDominant boolean flag to signal if RESET shall be dominant (true) or SET shall be dominant (false)
119 ClockedFlipFlopImplementation( bool rIsDominant = true ) : RSFlipFlopImplementation( rIsDominant ), _clock(false) {}
122 * @brief evaluates the output state from the input lines, basically waits for a raising edge and calls onRaisingEdge
123 * @param dt the elapsed time in seconds from since the last call
124 * @param input a map of named input lines
125 * @param q a reference to a boolean variable to receive the output state
126 * @return true if the state has changed, false otherwise
128 virtual bool getState( double dt, DigitalComponent::InputMap input, bool & q );
131 class JKFlipFlopImplementation : public ClockedFlipFlopImplementation {
133 JKFlipFlopImplementation( bool rIsDominant = true ) : ClockedFlipFlopImplementation ( rIsDominant ) {}
134 virtual bool onRaisingEdge( DigitalComponent::InputMap input, bool & q );
137 class DFlipFlopImplementation : public ClockedFlipFlopImplementation {
139 DFlipFlopImplementation( bool rIsDominant = true ) : ClockedFlipFlopImplementation ( rIsDominant ) {}
140 virtual bool onRaisingEdge( DigitalComponent::InputMap input, bool & q ) {
141 q = input.get_value("D");
146 class TFlipFlopImplementation : public ClockedFlipFlopImplementation {
148 TFlipFlopImplementation( bool rIsDominant = true ) : ClockedFlipFlopImplementation ( rIsDominant ) {}
149 virtual bool onRaisingEdge( DigitalComponent::InputMap input, bool & q ) {
155 class MonoFlopImplementation : public JKFlipFlopImplementation {
157 virtual bool configure( const std::string & nodeName, SGPropertyNode_ptr configNode );
158 InputValueList _time;
161 MonoFlopImplementation( bool rIsDominant = true ) : JKFlipFlopImplementation( rIsDominant ) {}
162 virtual bool getState( double dt, DigitalComponent::InputMap input, bool & q );
165 bool MonoFlopImplementation::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
167 if( JKFlipFlopImplementation::configure( nodeName, configNode ) )
170 if (nodeName == "time") {
171 _time.push_back( new InputValue( configNode ) );
178 bool MonoFlopImplementation::getState( double dt, DigitalComponent::InputMap input, bool & q )
180 if( JKFlipFlopImplementation::getState( dt, input, q ) ) {
181 _t = q ? _time.get_value() : 0;
195 bool RSFlipFlopImplementation::getState( double dt, DigitalComponent::InputMap input, bool & q )
197 bool s = input.get_value("S");
198 bool r = input.get_value("R");
200 // s == false && q == false: no change, keep state
202 if( _rIsDominant ) { // RS: reset is dominant
203 if( s ) q = true; // set
204 if( r ) q = false; // reset
205 } else { // SR: set is dominant
206 if( r ) q = false; // reset
207 if( s ) q = true; // set
209 return true; // signal state changed
211 return false; // signal state unchagned
214 bool ClockedFlipFlopImplementation::getState( double dt, DigitalComponent::InputMap input, bool & q )
216 if( RSFlipFlopImplementation::getState( dt, input, q ) )
219 bool c = input.get_value("clock");
220 bool raisingEdge = c && !_clock;
224 if( !raisingEdge ) return false; //signal no change
225 return onRaisingEdge( input, q );
228 bool JKFlipFlopImplementation::onRaisingEdge( DigitalComponent::InputMap input, bool & q )
230 bool j = input.get_value("J");
231 bool k = input.get_value("K");
233 // j == false && k == false: no change, keep state
238 if( j ) q = true; // set
239 if( k ) q = false; // reset
241 return true; // signal state changed
244 return false; // signal no change
247 bool FlipFlopImplementation::configure( SGPropertyNode_ptr configNode )
249 for (int i = 0; i < configNode->nChildren(); ++i ) {
250 SGPropertyNode_ptr prop;
252 SGPropertyNode_ptr child = configNode->getChild(i);
253 string cname(child->getName());
255 if( configure( cname, child ) )
258 } // for configNode->nChildren()
264 static map<string,FunctorBase<FlipFlopImplementation> *> componentForge;
266 bool FlipFlop::configure( const std::string & nodeName, SGPropertyNode_ptr configNode )
268 if( componentForge.empty() ) {
269 componentForge["RS"] = new CreateAndConfigureFunctor<RSFlipFlopImplementation,FlipFlopImplementation>();
270 componentForge["SR"] = new CreateAndConfigureFunctor<SRFlipFlopImplementation,FlipFlopImplementation>();
271 componentForge["JK"] = new CreateAndConfigureFunctor<JKFlipFlopImplementation,FlipFlopImplementation>();
272 componentForge["D"] = new CreateAndConfigureFunctor<DFlipFlopImplementation, FlipFlopImplementation>();
273 componentForge["T"] = new CreateAndConfigureFunctor<TFlipFlopImplementation, FlipFlopImplementation>();
274 componentForge["monostable"] = new CreateAndConfigureFunctor<MonoFlopImplementation, FlipFlopImplementation>();
277 if( DigitalComponent::configure( nodeName, configNode ) )
280 if( nodeName == "type" ) {
281 string type(configNode->getStringValue());
282 if( componentForge.count(type) == 0 ) {
283 SG_LOG( SG_AUTOPILOT, SG_BULK, "unhandled flip-flop type <" << type << ">" << endl );
286 _implementation = (*componentForge[type])( configNode->getParent() );
290 if (nodeName == "set"||nodeName == "S") {
291 _input["S"] = sgReadCondition( fgGetNode("/"), configNode );
295 if (nodeName == "reset" || nodeName == "R" ) {
296 _input["R"] = sgReadCondition( fgGetNode("/"), configNode );
300 if (nodeName == "J") {
301 _input["J"] = sgReadCondition( fgGetNode("/"), configNode );
305 if (nodeName == "K") {
306 _input["K"] = sgReadCondition( fgGetNode("/"), configNode );
310 if (nodeName == "D") {
311 _input["D"] = sgReadCondition( fgGetNode("/"), configNode );
315 if (nodeName == "clock") {
316 _input["clock"] = sgReadCondition( fgGetNode("/"), configNode );
323 void FlipFlop::update( bool firstTime, double dt )
325 if( _implementation == NULL ) {
326 SG_LOG( SG_AUTOPILOT, SG_ALERT, "No flip-flop implementation for " << get_name() << endl );
332 q0 = q = get_output();
334 if( _implementation->getState( dt, _input, q ) ) {
338 cout << "updating flip-flop \"" << get_name() << "\"" << endl;
339 cout << "prev. Output:" << q0 << endl;
340 for( InputMap::const_iterator it = _input.begin(); it != _input.end(); it++ )
341 cout << "Input \"" << (*it).first << "\":" << (*it).second->test() << endl;
342 cout << "new Output:" << q << endl;