summaryrefslogtreecommitdiffstats
path: root/src/electronics/switch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/electronics/switch.cpp')
-rw-r--r--src/electronics/switch.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/electronics/switch.cpp b/src/electronics/switch.cpp
new file mode 100644
index 0000000..7cbda70
--- /dev/null
+++ b/src/electronics/switch.cpp
@@ -0,0 +1,221 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "circuitdocument.h"
+#include "component.h"
+#include "ecnode.h"
+#include "pin.h"
+#include "resistance.h"
+#include "simulator.h"
+#include "switch.h"
+
+#include <kdebug.h>
+#include <qtimer.h>
+
+#include <cmath>
+#include <stdlib.h> // for rand
+#include <time.h>
+
+Switch::Switch( Component * parent, Pin * p1, Pin * p2, State state )
+{
+ m_bouncePeriod_ms = 5;
+ m_bBounce = false;
+ m_bounceStart = 0;
+ m_pBounceResistance = 0l;
+ m_pP1 = p1;
+ m_pP2 = p2;
+ m_pComponent = parent;
+ m_pStopBouncingTimer = new QTimer( this );
+ connect( m_pStopBouncingTimer, SIGNAL(timeout()), this, SLOT(stopBouncing()) );
+
+ // Force update
+ m_state = (state == Open) ? Closed : Open;
+ setState(state);
+}
+
+
+Switch::~ Switch( )
+{
+ if (m_pP1)
+ m_pP1->setSwitchConnected( m_pP2, false );
+
+ if (m_pP2)
+ m_pP2->setSwitchConnected( m_pP1, false );
+}
+
+
+void Switch::setState( State state )
+{
+ if ( m_state == state )
+ return;
+
+ m_state = state;
+
+ if ( m_bBounce )
+ startBouncing();
+ else
+ {
+ // I'm being lazy...calling stopBouncing will connect the stuff
+ stopBouncing();
+ }
+}
+
+
+void Switch::setBounce( bool bounce, int msec )
+{
+ m_bBounce = bounce;
+ m_bouncePeriod_ms = msec;
+}
+
+
+void Switch::startBouncing()
+{
+ if ( m_pBounceResistance )
+ {
+ // Already active?
+ return;
+ }
+
+ CircuitDocument * cd = m_pComponent->circuitDocument();
+ if ( !cd )
+ return;
+
+// kdDebug() << k_funcinfo << endl;
+
+ m_pBounceResistance = m_pComponent->createResistance( m_pP1, m_pP2, 10000 );
+ m_bounceStart = Simulator::self()->time();
+ Simulator::self()->attachSwitch( this );
+// kdDebug() << "m_bounceStart="<<m_bounceStart<<" m_bouncePeriod_ms="<<m_bouncePeriod_ms<<endl;
+
+ // initialize random generator
+ srand ( time(NULL) );
+
+ // Give our bounce resistor an initial value
+ bounce();
+}
+
+
+void Switch::bounce()
+{
+ int bounced_ms = (( Simulator::self()->time() - m_bounceStart ) * 1000) / LOGIC_UPDATE_RATE;
+ if ( bounced_ms >= m_bouncePeriod_ms )
+ {
+ if ( !m_pStopBouncingTimer->isActive() )
+ m_pStopBouncingTimer->start( 0, true );
+ return;
+ }
+
+ double g = double(rand())/double(RAND_MAX);
+
+ // 4th power of the conductance seems to give a nice distribution
+ g = g * g * g * g;
+
+ m_pBounceResistance->setConductance( g );
+}
+
+
+void Switch::stopBouncing()
+{
+ Simulator::self()->detachSwitch( this );
+ m_pComponent->removeElement( m_pBounceResistance, true );
+ m_pBounceResistance = 0l;
+
+ bool connected = (m_state == Closed);
+
+ if ( m_pP1 && m_pP2 )
+ {
+ m_pP1->setSwitchConnected( m_pP2, connected );
+ m_pP2->setSwitchConnected( m_pP1, connected );
+ }
+
+ if ( CircuitDocument * cd = m_pComponent->circuitDocument() )
+ cd->requestAssignCircuits();
+}
+
+
+bool Switch::calculateCurrent()
+{
+ if ( !m_pP1 || !m_pP2 )
+ return false;
+
+ if ( state() == Open )
+ {
+ m_pP1->setSwitchCurrentKnown( this );
+ m_pP2->setSwitchCurrentKnown( this );
+ return true;
+ }
+
+ Pin * pins[2] = { m_pP1, m_pP2 };
+
+ double current = 0.0;
+ bool currentKnown = false;
+
+ int pol;
+ for ( unsigned i = 0; i < 2; ++i )
+ {
+ pol = (i == 0) ? 1 : -1;
+
+ const WireList inputs = pins[i]->inputWireList();
+ const WireList outputs = pins[i]->outputWireList();
+
+ currentKnown = true;
+ current = 0.0;
+
+ WireList::const_iterator end = inputs.end();
+ for ( WireList::const_iterator it = inputs.begin(); it != end; ++it )
+ {
+ if ( !(*it) )
+ continue;
+
+ if ( !(*it)->currentIsKnown() )
+ {
+ currentKnown = false;
+ break;
+ }
+
+ current += (*it)->current();
+ }
+
+ if ( !currentKnown )
+ continue;
+
+ end = outputs.end();
+ for ( WireList::const_iterator it = outputs.begin(); it != end; ++it )
+ {
+ if ( !(*it) )
+ continue;
+
+ if ( !(*it)->currentIsKnown() )
+ {
+ currentKnown = false;
+ break;
+ }
+
+ current -= (*it)->current();
+ }
+
+ if ( currentKnown )
+ break;
+ }
+
+ if ( !currentKnown )
+ return false;
+
+ m_pP1->setSwitchCurrentKnown( this );
+ m_pP2->setSwitchCurrentKnown( this );
+ m_pP1->mergeCurrent( -current * pol );
+ m_pP2->mergeCurrent( current * pol );
+
+ return true;
+}
+
+#include "switch.moc"
+
+