diff options
Diffstat (limited to 'src/electronics/switch.cpp')
-rw-r--r-- | src/electronics/switch.cpp | 221 |
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" + + |