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" + + | 
