switch.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005 by David Saxton                                    *
00003  *   david@bluehaze.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010 
00011 #include "circuitdocument.h"
00012 #include "component.h"
00013 #include "ecnode.h"
00014 #include "pin.h"
00015 #include "resistance.h"
00016 #include "simulator.h"
00017 #include "switch.h"
00018 
00019 #include <kdebug.h>
00020 #include <qtimer.h>
00021 
00022 #include <cmath>
00023 #include <stdlib.h> // for rand
00024 #include <time.h>
00025 
00026 Switch::Switch( Component * parent, Pin * p1, Pin * p2, State state )
00027 {
00028         m_bouncePeriod_ms = 5;
00029         m_bBounce = false;
00030         m_bounceStart = 0;
00031         m_pBounceResistance = 0;
00032         m_pP1 = p1;
00033         m_pP2 = p2;
00034         m_pComponent = parent;
00035         m_pStopBouncingTimer = new QTimer( this );
00036         connect( m_pStopBouncingTimer, SIGNAL(timeout()), this, SLOT(stopBouncing()) );
00037         
00038         // Force update
00039         m_state = (state == Open) ? Closed : Open;
00040         setState(state);
00041 }
00042 
00043 
00044 Switch::~ Switch( )
00045 {
00046         if (m_pP1)
00047                 m_pP1->setSwitchConnected( m_pP2, false );
00048         
00049         if (m_pP2)
00050                 m_pP2->setSwitchConnected( m_pP1, false );
00051 }
00052 
00053 
00054 void Switch::setState( State state )
00055 {
00056         if ( m_state == state )
00057                 return;
00058         
00059         m_state = state;
00060         
00061         if ( m_bBounce )
00062                 startBouncing();
00063         else
00064         {
00065                 // I'm being lazy...calling stopBouncing will connect the stuff
00066                 stopBouncing();
00067         }
00068 }
00069 
00070 
00071 void Switch::setBounce( bool bounce, int msec )
00072 {
00073         m_bBounce = bounce;
00074         m_bouncePeriod_ms = msec;
00075 }
00076 
00077 
00078 void Switch::startBouncing()
00079 {
00080         if ( m_pBounceResistance )
00081         {
00082                 // Already active?
00083                 return;
00084         }
00085         
00086         CircuitDocument * cd = m_pComponent->circuitDocument();
00087         if ( !cd )
00088                 return;
00089         
00090 //      kdDebug() << k_funcinfo << endl;
00091         
00092         m_pBounceResistance = m_pComponent->createResistance( m_pP1, m_pP2, 10000 );
00093         m_bounceStart = Simulator::self()->time();
00094         Simulator::self()->attachSwitch(this);
00095 //      kdDebug() << "m_bounceStart="<<m_bounceStart<<" m_bouncePeriod_ms="<<m_bouncePeriod_ms<<endl;
00096         
00097         // initialize random generator
00098         srand ( time(NULL) );
00099         
00100         // Give our bounce resistor an initial value
00101         bounce();
00102 }
00103 
00104 
00105 void Switch::bounce()
00106 {
00107         int bounced_ms = (( Simulator::self()->time() - m_bounceStart ) * 1000) / LOGIC_UPDATE_RATE;
00108         if ( bounced_ms >= m_bouncePeriod_ms )
00109         {
00110                 if ( !m_pStopBouncingTimer->isActive() )
00111                         m_pStopBouncingTimer->start( 0, true );
00112                 return;
00113         }
00114         
00115         double g = double(rand())/double(RAND_MAX);
00116         
00117         // 4th power of the conductance seems to give a nice distribution
00118         g = g * g * g * g;
00119         
00120         m_pBounceResistance->setConductance( g );
00121 }
00122 
00123 
00124 void Switch::stopBouncing()
00125 {
00126         Simulator::self()->detachSwitch(this );
00127         m_pComponent->removeElement( m_pBounceResistance, true );
00128         m_pBounceResistance = 0;
00129         
00130         bool connected = (m_state == Closed);
00131         
00132         if ( m_pP1 && m_pP2 )
00133         {
00134                 m_pP1->setSwitchConnected( m_pP2, connected );
00135                 m_pP2->setSwitchConnected( m_pP1, connected );
00136         }
00137         
00138         if ( CircuitDocument * cd = m_pComponent->circuitDocument() )
00139                 cd->requestAssignCircuits();
00140 }
00141 
00142 
00143 bool Switch::calculateCurrent()
00144 {
00145         if ( !m_pP1 || !m_pP2 )
00146                 return false;
00147         
00148         if ( state() == Open )
00149         {
00150                 m_pP1->setSwitchCurrentKnown( this );
00151                 m_pP2->setSwitchCurrentKnown( this );
00152                 return true;
00153         }
00154         
00155         Pin * pins[2] = { m_pP1, m_pP2 };
00156         
00157         double current = 0.0;
00158         bool currentKnown = false;
00159         
00160         int pol;
00161         for ( unsigned i = 0; i < 2; ++i )
00162         {
00163                 pol = (i == 0) ? 1 : -1;
00164                 
00165                 const WireList inputs = pins[i]->inputWireList();
00166                 const WireList outputs = pins[i]->outputWireList();
00167                 
00168                 currentKnown = true;
00169                 current = 0.0;
00170                 
00171                 WireList::const_iterator end = inputs.end();
00172                 for ( WireList::const_iterator it = inputs.begin(); it != end; ++it )
00173                 {
00174                         if ( !(*it) )
00175                                 continue;
00176                         
00177                         if ( !(*it)->currentIsKnown() )
00178                         {
00179                                 currentKnown = false;
00180                                 break;
00181                         }
00182                         
00183                         current += (*it)->current();
00184                 }
00185                 
00186                 if ( !currentKnown )
00187                         continue;
00188                 
00189                 end = outputs.end();
00190                 for ( WireList::const_iterator it = outputs.begin(); it != end; ++it )
00191                 {
00192                         if ( !(*it) )
00193                                 continue;
00194                         
00195                         if ( !(*it)->currentIsKnown() )
00196                         {
00197                                 currentKnown = false;
00198                                 break;
00199                         }
00200                         
00201                         current -= (*it)->current();
00202                 }
00203                 
00204                 if ( currentKnown )
00205                         break;
00206         }
00207         
00208         if ( !currentKnown )
00209                 return false;
00210         
00211         m_pP1->setSwitchCurrentKnown( this );
00212         m_pP2->setSwitchCurrentKnown( this );
00213         m_pP1->mergeCurrent( -current * pol );
00214         m_pP2->mergeCurrent( current * pol );
00215         
00216         return true;
00217 }
00218 
00219 #include "switch.moc"
00220 
00221 

Generated on Tue May 8 17:05:32 2007 for KTechLab by  doxygen 1.5.1