Logo Search packages:      
Sourcecode: ktechlab version File versions  Download package

switch.cpp

/***************************************************************************
 *   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 );
}


00054 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();
      }
}


00071 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();
}


00105 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 );
}


00124 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();
}


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



Generated by  Doxygen 1.6.0   Back to index