From 5de3dd4762ca33a0f92e79ffa4fe2ff67069d531 Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 24 Feb 2010 01:49:02 +0000 Subject: Added KDE3 version of ktechlab git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktechlab@1095338 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- src/electronics/Makefile.am | 18 + src/electronics/component.cpp | 1017 ++++++++++++++++++++ src/electronics/component.h | 362 +++++++ src/electronics/components/Makefile.am | 33 + src/electronics/components/addac.cpp | 281 ++++++ src/electronics/components/addac.h | 93 ++ src/electronics/components/bidirled.cpp | 157 +++ src/electronics/components/bidirled.h | 45 + src/electronics/components/binarycounter.cpp | 186 ++++ src/electronics/components/binarycounter.h | 63 ++ src/electronics/components/bussplitter.cpp | 133 +++ src/electronics/components/bussplitter.h | 45 + src/electronics/components/demultiplexer.cpp | 175 ++++ src/electronics/components/demultiplexer.h | 46 + src/electronics/components/dependentsource.cpp | 314 ++++++ src/electronics/components/dependentsource.h | 112 +++ src/electronics/components/discretelogic.cpp | 308 ++++++ src/electronics/components/discretelogic.h | 110 +++ src/electronics/components/ec555.cpp | 172 ++++ src/electronics/components/ec555.h | 56 ++ src/electronics/components/ecbcdto7segment.cpp | 158 +++ src/electronics/components/ecbcdto7segment.h | 41 + src/electronics/components/ecbjt.cpp | 153 +++ src/electronics/components/ecbjt.h | 42 + src/electronics/components/eccapacitor.cpp | 92 ++ src/electronics/components/eccapacitor.h | 40 + src/electronics/components/ecclockinput.cpp | 185 ++++ src/electronics/components/ecclockinput.h | 56 ++ src/electronics/components/eccurrentsignal.cpp | 92 ++ src/electronics/components/eccurrentsignal.h | 36 + src/electronics/components/eccurrentsource.cpp | 94 ++ src/electronics/components/eccurrentsource.h | 36 + src/electronics/components/ecdiode.cpp | 120 +++ src/electronics/components/ecdiode.h | 35 + src/electronics/components/ecfixedvoltage.cpp | 77 ++ src/electronics/components/ecfixedvoltage.h | 35 + src/electronics/components/ecground.cpp | 66 ++ src/electronics/components/ecground.h | 33 + src/electronics/components/eckeypad.cpp | 199 ++++ src/electronics/components/eckeypad.h | 42 + src/electronics/components/ecled.cpp | 134 +++ src/electronics/components/ecled.h | 48 + src/electronics/components/ecopamp.cpp | 85 ++ src/electronics/components/ecopamp.h | 35 + src/electronics/components/ecpotentiometer.cpp | 119 +++ src/electronics/components/ecpotentiometer.h | 43 + src/electronics/components/ecresistor.cpp | 76 ++ src/electronics/components/ecresistor.h | 36 + src/electronics/components/ecsevensegment.cpp | 210 ++++ src/electronics/components/ecsevensegment.h | 50 + src/electronics/components/ecsignallamp.cpp | 86 ++ src/electronics/components/ecsignallamp.h | 40 + src/electronics/components/ecsubcircuit.cpp | 130 +++ src/electronics/components/ecsubcircuit.h | 61 ++ src/electronics/components/ecvoltagesignal.cpp | 95 ++ src/electronics/components/ecvoltagesignal.h | 36 + src/electronics/components/ecvoltagesource.cpp | 93 ++ src/electronics/components/ecvoltagesource.h | 37 + src/electronics/components/externalconnection.cpp | 78 ++ src/electronics/components/externalconnection.h | 35 + src/electronics/components/flipflop.cpp | 347 +++++++ src/electronics/components/flipflop.h | 107 ++ src/electronics/components/fulladder.cpp | 91 ++ src/electronics/components/fulladder.h | 37 + src/electronics/components/inductor.cpp | 84 ++ src/electronics/components/inductor.h | 35 + src/electronics/components/magnitudecomparator.cpp | 206 ++++ src/electronics/components/magnitudecomparator.h | 50 + src/electronics/components/matrixdisplay.cpp | 291 ++++++ src/electronics/components/matrixdisplay.h | 60 ++ src/electronics/components/matrixdisplaydriver.cpp | 380 ++++++++ src/electronics/components/matrixdisplaydriver.h | 42 + src/electronics/components/meter.cpp | 265 +++++ src/electronics/components/meter.h | 103 ++ src/electronics/components/multiinputgate.cpp | 530 ++++++++++ src/electronics/components/multiinputgate.h | 160 +++ src/electronics/components/multiplexer.cpp | 176 ++++ src/electronics/components/multiplexer.h | 46 + .../components/parallelportcomponent.cpp | 241 +++++ src/electronics/components/parallelportcomponent.h | 49 + src/electronics/components/piccomponent.cpp | 437 +++++++++ src/electronics/components/piccomponent.h | 97 ++ src/electronics/components/piccomponentpin.cpp | 172 ++++ src/electronics/components/piccomponentpin.h | 68 ++ src/electronics/components/probe.cpp | 291 ++++++ src/electronics/components/probe.h | 113 +++ src/electronics/components/pushswitch.cpp | 204 ++++ src/electronics/components/pushswitch.h | 62 ++ src/electronics/components/ram.cpp | 232 +++++ src/electronics/components/ram.h | 51 + src/electronics/components/resistordip.cpp | 132 +++ src/electronics/components/resistordip.h | 43 + src/electronics/components/rotoswitch.cpp | 317 ++++++ src/electronics/components/rotoswitch.h | 70 ++ src/electronics/components/serialportcomponent.cpp | 242 +++++ src/electronics/components/serialportcomponent.h | 61 ++ src/electronics/components/toggleswitch.cpp | 407 ++++++++ src/electronics/components/toggleswitch.h | 116 +++ src/electronics/ecnode.cpp | 239 +++++ src/electronics/ecnode.h | 74 ++ src/electronics/gpsimprocessor.cpp | 880 +++++++++++++++++ src/electronics/gpsimprocessor.h | 393 ++++++++ src/electronics/pin.cpp | 175 ++++ src/electronics/pin.h | 211 ++++ src/electronics/port.cpp | 514 ++++++++++ src/electronics/port.h | 248 +++++ src/electronics/simulation/Makefile.am | 11 + src/electronics/simulation/bjt.cpp | 257 +++++ src/electronics/simulation/bjt.h | 75 ++ src/electronics/simulation/capacitance.cpp | 117 +++ src/electronics/simulation/capacitance.h | 55 ++ src/electronics/simulation/cccs.cpp | 89 ++ src/electronics/simulation/cccs.h | 41 + src/electronics/simulation/ccvs.cpp | 91 ++ src/electronics/simulation/ccvs.h | 41 + src/electronics/simulation/circuit.cpp | 550 +++++++++++ src/electronics/simulation/circuit.h | 137 +++ src/electronics/simulation/currentsignal.cpp | 67 ++ src/electronics/simulation/currentsignal.h | 43 + src/electronics/simulation/currentsource.cpp | 64 ++ src/electronics/simulation/currentsource.h | 39 + src/electronics/simulation/diode.cpp | 198 ++++ src/electronics/simulation/diode.h | 73 ++ src/electronics/simulation/element.cpp | 193 ++++ src/electronics/simulation/element.h | 255 +++++ src/electronics/simulation/elementset.cpp | 253 +++++ src/electronics/simulation/elementset.h | 131 +++ src/electronics/simulation/elementsignal.cpp | 64 ++ src/electronics/simulation/elementsignal.h | 45 + src/electronics/simulation/inductance.cpp | 126 +++ src/electronics/simulation/inductance.h | 55 ++ src/electronics/simulation/logic.cpp | 319 ++++++ src/electronics/simulation/logic.h | 211 ++++ src/electronics/simulation/matrix.cpp | 546 +++++++++++ src/electronics/simulation/matrix.h | 248 +++++ src/electronics/simulation/nonlinear.cpp | 97 ++ src/electronics/simulation/nonlinear.h | 48 + src/electronics/simulation/opamp.cpp | 77 ++ src/electronics/simulation/opamp.h | 36 + src/electronics/simulation/reactive.cpp | 36 + src/electronics/simulation/reactive.h | 42 + src/electronics/simulation/resistance.cpp | 95 ++ src/electronics/simulation/resistance.h | 43 + src/electronics/simulation/vccs.cpp | 93 ++ src/electronics/simulation/vccs.h | 40 + src/electronics/simulation/vcvs.cpp | 93 ++ src/electronics/simulation/vcvs.h | 40 + src/electronics/simulation/vec.cpp | 166 ++++ src/electronics/simulation/vec.h | 109 +++ src/electronics/simulation/voltagepoint.cpp | 73 ++ src/electronics/simulation/voltagepoint.h | 39 + src/electronics/simulation/voltagesignal.cpp | 79 ++ src/electronics/simulation/voltagesignal.h | 41 + src/electronics/simulation/voltagesource.cpp | 77 ++ src/electronics/simulation/voltagesource.h | 38 + src/electronics/subcircuits.cpp | 175 ++++ src/electronics/subcircuits.h | 76 ++ src/electronics/switch.cpp | 221 +++++ src/electronics/switch.h | 86 ++ src/electronics/wire.cpp | 146 +++ src/electronics/wire.h | 64 ++ 161 files changed, 22558 insertions(+) create mode 100644 src/electronics/Makefile.am create mode 100644 src/electronics/component.cpp create mode 100644 src/electronics/component.h create mode 100644 src/electronics/components/Makefile.am create mode 100644 src/electronics/components/addac.cpp create mode 100644 src/electronics/components/addac.h create mode 100644 src/electronics/components/bidirled.cpp create mode 100644 src/electronics/components/bidirled.h create mode 100644 src/electronics/components/binarycounter.cpp create mode 100644 src/electronics/components/binarycounter.h create mode 100644 src/electronics/components/bussplitter.cpp create mode 100644 src/electronics/components/bussplitter.h create mode 100644 src/electronics/components/demultiplexer.cpp create mode 100644 src/electronics/components/demultiplexer.h create mode 100644 src/electronics/components/dependentsource.cpp create mode 100644 src/electronics/components/dependentsource.h create mode 100644 src/electronics/components/discretelogic.cpp create mode 100644 src/electronics/components/discretelogic.h create mode 100644 src/electronics/components/ec555.cpp create mode 100644 src/electronics/components/ec555.h create mode 100644 src/electronics/components/ecbcdto7segment.cpp create mode 100644 src/electronics/components/ecbcdto7segment.h create mode 100644 src/electronics/components/ecbjt.cpp create mode 100644 src/electronics/components/ecbjt.h create mode 100644 src/electronics/components/eccapacitor.cpp create mode 100644 src/electronics/components/eccapacitor.h create mode 100644 src/electronics/components/ecclockinput.cpp create mode 100644 src/electronics/components/ecclockinput.h create mode 100644 src/electronics/components/eccurrentsignal.cpp create mode 100644 src/electronics/components/eccurrentsignal.h create mode 100644 src/electronics/components/eccurrentsource.cpp create mode 100644 src/electronics/components/eccurrentsource.h create mode 100644 src/electronics/components/ecdiode.cpp create mode 100644 src/electronics/components/ecdiode.h create mode 100644 src/electronics/components/ecfixedvoltage.cpp create mode 100644 src/electronics/components/ecfixedvoltage.h create mode 100644 src/electronics/components/ecground.cpp create mode 100644 src/electronics/components/ecground.h create mode 100644 src/electronics/components/eckeypad.cpp create mode 100644 src/electronics/components/eckeypad.h create mode 100644 src/electronics/components/ecled.cpp create mode 100644 src/electronics/components/ecled.h create mode 100644 src/electronics/components/ecopamp.cpp create mode 100644 src/electronics/components/ecopamp.h create mode 100644 src/electronics/components/ecpotentiometer.cpp create mode 100644 src/electronics/components/ecpotentiometer.h create mode 100644 src/electronics/components/ecresistor.cpp create mode 100644 src/electronics/components/ecresistor.h create mode 100644 src/electronics/components/ecsevensegment.cpp create mode 100644 src/electronics/components/ecsevensegment.h create mode 100644 src/electronics/components/ecsignallamp.cpp create mode 100644 src/electronics/components/ecsignallamp.h create mode 100644 src/electronics/components/ecsubcircuit.cpp create mode 100644 src/electronics/components/ecsubcircuit.h create mode 100644 src/electronics/components/ecvoltagesignal.cpp create mode 100644 src/electronics/components/ecvoltagesignal.h create mode 100644 src/electronics/components/ecvoltagesource.cpp create mode 100644 src/electronics/components/ecvoltagesource.h create mode 100644 src/electronics/components/externalconnection.cpp create mode 100644 src/electronics/components/externalconnection.h create mode 100644 src/electronics/components/flipflop.cpp create mode 100644 src/electronics/components/flipflop.h create mode 100644 src/electronics/components/fulladder.cpp create mode 100644 src/electronics/components/fulladder.h create mode 100644 src/electronics/components/inductor.cpp create mode 100644 src/electronics/components/inductor.h create mode 100644 src/electronics/components/magnitudecomparator.cpp create mode 100644 src/electronics/components/magnitudecomparator.h create mode 100644 src/electronics/components/matrixdisplay.cpp create mode 100644 src/electronics/components/matrixdisplay.h create mode 100644 src/electronics/components/matrixdisplaydriver.cpp create mode 100644 src/electronics/components/matrixdisplaydriver.h create mode 100644 src/electronics/components/meter.cpp create mode 100644 src/electronics/components/meter.h create mode 100644 src/electronics/components/multiinputgate.cpp create mode 100644 src/electronics/components/multiinputgate.h create mode 100644 src/electronics/components/multiplexer.cpp create mode 100644 src/electronics/components/multiplexer.h create mode 100644 src/electronics/components/parallelportcomponent.cpp create mode 100644 src/electronics/components/parallelportcomponent.h create mode 100644 src/electronics/components/piccomponent.cpp create mode 100644 src/electronics/components/piccomponent.h create mode 100644 src/electronics/components/piccomponentpin.cpp create mode 100644 src/electronics/components/piccomponentpin.h create mode 100644 src/electronics/components/probe.cpp create mode 100644 src/electronics/components/probe.h create mode 100644 src/electronics/components/pushswitch.cpp create mode 100644 src/electronics/components/pushswitch.h create mode 100644 src/electronics/components/ram.cpp create mode 100644 src/electronics/components/ram.h create mode 100644 src/electronics/components/resistordip.cpp create mode 100644 src/electronics/components/resistordip.h create mode 100644 src/electronics/components/rotoswitch.cpp create mode 100644 src/electronics/components/rotoswitch.h create mode 100644 src/electronics/components/serialportcomponent.cpp create mode 100644 src/electronics/components/serialportcomponent.h create mode 100644 src/electronics/components/toggleswitch.cpp create mode 100644 src/electronics/components/toggleswitch.h create mode 100644 src/electronics/ecnode.cpp create mode 100644 src/electronics/ecnode.h create mode 100644 src/electronics/gpsimprocessor.cpp create mode 100644 src/electronics/gpsimprocessor.h create mode 100644 src/electronics/pin.cpp create mode 100644 src/electronics/pin.h create mode 100644 src/electronics/port.cpp create mode 100644 src/electronics/port.h create mode 100644 src/electronics/simulation/Makefile.am create mode 100644 src/electronics/simulation/bjt.cpp create mode 100644 src/electronics/simulation/bjt.h create mode 100644 src/electronics/simulation/capacitance.cpp create mode 100644 src/electronics/simulation/capacitance.h create mode 100644 src/electronics/simulation/cccs.cpp create mode 100644 src/electronics/simulation/cccs.h create mode 100644 src/electronics/simulation/ccvs.cpp create mode 100644 src/electronics/simulation/ccvs.h create mode 100644 src/electronics/simulation/circuit.cpp create mode 100644 src/electronics/simulation/circuit.h create mode 100644 src/electronics/simulation/currentsignal.cpp create mode 100644 src/electronics/simulation/currentsignal.h create mode 100644 src/electronics/simulation/currentsource.cpp create mode 100644 src/electronics/simulation/currentsource.h create mode 100644 src/electronics/simulation/diode.cpp create mode 100644 src/electronics/simulation/diode.h create mode 100644 src/electronics/simulation/element.cpp create mode 100644 src/electronics/simulation/element.h create mode 100644 src/electronics/simulation/elementset.cpp create mode 100644 src/electronics/simulation/elementset.h create mode 100644 src/electronics/simulation/elementsignal.cpp create mode 100644 src/electronics/simulation/elementsignal.h create mode 100644 src/electronics/simulation/inductance.cpp create mode 100644 src/electronics/simulation/inductance.h create mode 100644 src/electronics/simulation/logic.cpp create mode 100644 src/electronics/simulation/logic.h create mode 100644 src/electronics/simulation/matrix.cpp create mode 100644 src/electronics/simulation/matrix.h create mode 100644 src/electronics/simulation/nonlinear.cpp create mode 100644 src/electronics/simulation/nonlinear.h create mode 100644 src/electronics/simulation/opamp.cpp create mode 100644 src/electronics/simulation/opamp.h create mode 100644 src/electronics/simulation/reactive.cpp create mode 100644 src/electronics/simulation/reactive.h create mode 100644 src/electronics/simulation/resistance.cpp create mode 100644 src/electronics/simulation/resistance.h create mode 100644 src/electronics/simulation/vccs.cpp create mode 100644 src/electronics/simulation/vccs.h create mode 100644 src/electronics/simulation/vcvs.cpp create mode 100644 src/electronics/simulation/vcvs.h create mode 100644 src/electronics/simulation/vec.cpp create mode 100644 src/electronics/simulation/vec.h create mode 100644 src/electronics/simulation/voltagepoint.cpp create mode 100644 src/electronics/simulation/voltagepoint.h create mode 100644 src/electronics/simulation/voltagesignal.cpp create mode 100644 src/electronics/simulation/voltagesignal.h create mode 100644 src/electronics/simulation/voltagesource.cpp create mode 100644 src/electronics/simulation/voltagesource.h create mode 100644 src/electronics/subcircuits.cpp create mode 100644 src/electronics/subcircuits.h create mode 100644 src/electronics/switch.cpp create mode 100644 src/electronics/switch.h create mode 100644 src/electronics/wire.cpp create mode 100644 src/electronics/wire.h (limited to 'src/electronics') diff --git a/src/electronics/Makefile.am b/src/electronics/Makefile.am new file mode 100644 index 0000000..c15e689 --- /dev/null +++ b/src/electronics/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/electronics \ + -I$(top_srcdir)/src/electronics/components -I$(top_srcdir)/src/electronics/simulation \ + -I$(top_srcdir)/src/flowparts -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \ + -I$(top_srcdir)/src/mechanics -I$(top_srcdir)/src/micro $(glib_cflags) $(all_includes) + +METASOURCES = AUTO + +SUBDIRS = simulation components + +noinst_LTLIBRARIES = libelectronics.la + +libelectronics_la_SOURCES = component.cpp subcircuits.cpp gpsimprocessor.cpp \ + switch.cpp pin.cpp wire.cpp ecnode.cpp port.cpp + +libelectronics_la_LIBADD = \ + $(top_builddir)/src/electronics/simulation/libelements.la $(top_builddir)/src/electronics/components/libcomponents.la + +noinst_HEADERS = gpsimprocessor.h switch.h pin.h wire.h ecnode.h port.h diff --git a/src/electronics/component.cpp b/src/electronics/component.cpp new file mode 100644 index 0000000..f9f3c12 --- /dev/null +++ b/src/electronics/component.cpp @@ -0,0 +1,1017 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "canvasitemparts.h" +#include "circuitdocument.h" +#include "component.h" +#include "src/core/ktlconfig.h" +#include "ecnode.h" +#include "itemdocumentdata.h" +#include "node.h" +#include "pin.h" +#include "simulator.h" + +#include "bjt.h" +#include "capacitance.h" +#include "cccs.h" +#include "ccvs.h" +#include "currentsignal.h" +#include "currentsource.h" +#include "diode.h" +#include "inductance.h" +#include "logic.h" +#include "opamp.h" +#include "resistance.h" +#include "switch.h" +#include "vccs.h" +#include "vcvs.h" +#include "voltagepoint.h" +#include "voltagesignal.h" +#include "voltagesource.h" + +#include +#include +#include +#include +#include +#include + +const int dipWidth = 112; +const int pairSep = 32; + +// Degrees per radian +static const double DPR = 57.29577951308232087665461840231273527024; + +Component::Component( ICNDocument *icnDocument, bool newItem, const QString &id ) + : CNItem( icnDocument, newItem, id ), + m_angleDegrees(0), + b_flipped(false) +{ + m_pCircuitDocument = dynamic_cast(icnDocument); + + for ( int i=0; i<4; ++i ) + { + m_pPNode[i] = 0l; + m_pNNode[i] = 0l; + } + + // Get configuration options + slotUpdateConfiguration(); + + // And finally register this :-) + icnDocument->registerItem(this); +} + +Component::~Component() +{ + removeElements(); + Simulator::self()->detachComponent(this); +} + +void Component::removeItem( ) +{ + if (b_deleted) + return; + Simulator::self()->detachComponent(this); + CNItem::removeItem(); +} + +void Component::removeElements( bool setPinsInterIndependent ) +{ + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + Element * e = (*it).e; + if (e) + { + emit elementDestroyed(e); + e->componentDeleted(); + } + } + m_elementMapList.clear(); + + const SwitchList::iterator swEnd = m_switchList.end(); + for ( SwitchList::iterator it = m_switchList.begin(); it != swEnd; ++it ) + { + Switch * sw = *it; + if ( !sw ) + continue; + + emit switchDestroyed( sw ); + delete sw; + } + m_switchList.clear(); + + if ( setPinsInterIndependent ) + setAllPinsInterIndependent(); +} + + +void Component::removeElement( Element * element, bool setPinsInterIndependent ) +{ + if (!element) + return; + + emit elementDestroyed(element); + element->componentDeleted(); + + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ) + { + ElementMapList::iterator next = it; + ++next; + + if ( (*it).e == element ) + m_elementMapList.remove(it); + + it = next; + } + + if ( setPinsInterIndependent ) + rebuildPinInterDepedence(); +} + + +void Component::removeSwitch( Switch * sw ) +{ + if ( !sw ) + return; + + emit switchDestroyed( sw ); + delete sw; + m_switchList.remove(sw); + m_pCircuitDocument->requestAssignCircuits(); +} + + +void Component::setNodalCurrents() +{ + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + ElementMap m = (*it); + for ( int i=0; i<4; i++ ) + { + if ( m.n[i] ) { + m.n[i]->mergeCurrent( m.e->m_cnodeI[i] ); + } + } + } +} + + +void Component::initPainter( QPainter &p ) +{ + CNItem::initPainter(p); + + if ( !b_flipped && (m_angleDegrees%360 == 0) ) + return; + + p.save(); + + p.translate( int(x()), int(y()) ); + if (b_flipped) + p.scale( -1, 1 ); + + p.rotate(m_angleDegrees); + p.translate( -int(x()), -int(y()) ); +} + + +void Component::deinitPainter( QPainter &p ) +{ + if ( !b_flipped && (m_angleDegrees%360 == 0) ) + return; + + p.restore(); +} + + +void Component::setAngleDegrees( int degrees ) +{ + updateConnectorPoints(false); + m_angleDegrees = degrees; + itemPointsChanged(); + updateAttachedPositioning(); + p_icnDocument->requestRerouteInvalidatedConnectors(); +} + + +void Component::setFlipped( bool flipped ) +{ + updateConnectorPoints(false); + b_flipped = flipped; + itemPointsChanged(); + updateAttachedPositioning(); + p_icnDocument->requestRerouteInvalidatedConnectors(); +} + + +void Component::itemPointsChanged() +{ + QPointArray transformedPoints = transMatrix( m_angleDegrees, b_flipped, 0, 0, false ).map(m_itemPoints); +// transformedPoints.translate( int(x()), int(y()) ); + setPoints(transformedPoints); +} + + +void Component::restoreFromItemData( const ItemData &itemData ) +{ + CNItem::restoreFromItemData(itemData); + + setAngleDegrees( int(itemData.angleDegrees) ); + setFlipped(itemData.flipped); +} + + +ItemData Component::itemData() const +{ + ItemData itemData = CNItem::itemData(); + itemData.angleDegrees = m_angleDegrees; + itemData.flipped = b_flipped; + return itemData; +} + + +QWMatrix Component::transMatrix( int angleDegrees, bool flipped, int x, int y, bool inverse ) +{ + QWMatrix m; + m.translate( x, y ); + if (inverse) + { + m.rotate(-angleDegrees); + if (flipped) + m.scale( -1, 1 ); + } + else + { + if (flipped) + m.scale( -1, 1 ); + m.rotate(angleDegrees); + } + m.translate( -x, -y ); + m.setTransformationMode( QWMatrix::Areas ); + return m; +} + + +void Component::finishedCreation() +{ + CNItem::finishedCreation(); + updateAttachedPositioning(); +} + + +void Component::updateAttachedPositioning() +{ + if (b_deleted || !m_bDoneCreation) + return; + + //BEGIN Transform the nodes + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + if ( !it.data().node ) + kdError() << k_funcinfo << "Node in nodemap is null" << endl; + else + { + int nx = int((std::cos(m_angleDegrees/DPR) * it.data().x) - (std::sin(m_angleDegrees/DPR) * it.data().y)); + int ny = int((std::sin(m_angleDegrees/DPR) * it.data().x) + (std::cos(m_angleDegrees/DPR) * it.data().y)); + + if (b_flipped) + nx = -nx; + +#define round_8(x) (((x) > 0) ? int(((x)+4)/8)*8 : int(((x)-4)/8)*8) + nx = round_8(nx); + ny = round_8(ny); +#undef round_8 + + int newDir = (((m_angleDegrees + it.data().orientation)%360)+360)%360; + if (b_flipped) + newDir = (((180-newDir)%360)+360)%360; + + it.data().node->move( nx+x(), ny+y() ); + it.data().node->setOrientation( (Node::node_dir)newDir ); + } + } + //END Transform the nodes + + + //BEGIN Transform the GuiParts + QWMatrix m; + + if (b_flipped) + m.scale( -1, 1 ); + m.rotate(m_angleDegrees); + m.setTransformationMode( QWMatrix::Areas ); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + QRect newPos = m.mapRect( it.data()->recommendedRect() ); + it.data()->move( newPos.x() + x(), newPos.y() + y() ); + it.data()->setGuiPartSize( newPos.width(), newPos.height() ); + it.data()->setAngleDegrees(m_angleDegrees); + } + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + QRect newPos = m.mapRect( it.data()->recommendedRect() ); + it.data()->move( newPos.x() + x(), newPos.y() + y() ); + it.data()->setGuiPartSize( newPos.width(), newPos.height() ); + it.data()->setAngleDegrees(m_angleDegrees); + } + //END Transform the GuiParts +} + + +void Component::drawPortShape( QPainter & p ) +{ + int h = height(); + int w = width() - 1; + int _x = int( x() + offsetX() ); + int _y = int( y() + offsetY() ); + + double roundSize = 8; + double slantIndent = 8; + + const double pi = 3.1415926536; + const double DPR = 180./pi; + double inner = std::atan(h/slantIndent); // Angle for slight corner + double outer = pi-inner; // Angle for sharp corner + + int inner16 = int(16*inner*DPR); + int outer16 = int(16*outer*DPR); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawPolygon( areaPoints() ); + p.restore(); + + initPainter( p ); + + // Left line + p.drawLine( int(_x), int(_y+roundSize/2), int(_x), int(_y+h-roundSize/2) ); + + // Right line + p.drawLine( int(_x+w), int(_y-slantIndent+h-roundSize/2), int(_x+w), int(_y+slantIndent+roundSize/2) ); + + // Bottom line + p.drawLine( int(_x+(1-std::cos(outer))*(roundSize/2)), int(_y+h+(std::sin(outer)-1)*(roundSize/2)), + int(_x+w+(std::cos(inner)-1)*(roundSize/2)), int(_y+h-slantIndent+(std::sin(inner)-1)*(roundSize/2)) ); + + // Top line + p.drawLine( int(_x+w+(std::cos(outer)-1)*(roundSize/2)), int(_y+slantIndent+(1-std::sin(inner))*(roundSize/2)), + int(_x+(1-std::cos(inner))*(roundSize/2)), int(_y+(1-std::sin(outer))*(roundSize/2)) ); + + + // Top left + p.drawArc( int(_x), int(_y), int(roundSize), int(roundSize), 90*16, outer16 ); + + // Bottom left + p.drawArc( int(_x), int(_y+h-roundSize), int(roundSize), int(roundSize), 180*16, outer16 ); + + // Top right + p.drawArc( int(_x+w-roundSize), int(_y+slantIndent), int(roundSize), int(roundSize), 0, inner16 ); + + // Bottom right + p.drawArc( int(_x+w-roundSize), int(_y-slantIndent+h-roundSize), int(roundSize), int(roundSize), 270*16, inner16 ); + + deinitPainter( p ); +} + + +void Component::initDIP( const QStringList & pins ) +{ + const int numPins = pins.size(); + const int numSide = numPins/2 + numPins%2; + + // Pins along left + for ( int i=0; i( p_icnDocument->nodeWithID( nodeId(ecNodeId) ) ); +} + + +void Component::slotUpdateConfiguration() +{ + const LogicConfig logicConfig = LogicIn::getConfig(); + + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + if ( LogicIn * logicIn = dynamic_cast((*it).e) ) + logicIn->setLogic(logicConfig); + } +} + + + +BJT * Component::createBJT( ECNode *c, ECNode *b, ECNode *e, bool isNPN ) +{ return createBJT( c->pin(), b->pin(), e->pin(), isNPN ); } +Capacitance * Component::createCapacitance( ECNode *n0, ECNode *n1, double capacitance ) +{ return createCapacitance( n0->pin(), n1->pin(), capacitance ); } +CCCS * Component::createCCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createCCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +CCVS * Component::createCCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createCCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +CurrentSignal * Component::createCurrentSignal( ECNode *n0, ECNode *n1, double current ) +{ return createCurrentSignal( n0->pin(), n1->pin(), current ); } +CurrentSource * Component::createCurrentSource( ECNode *n0, ECNode *n1, double current ) +{ return createCurrentSource( n0->pin(), n1->pin(), current ); } +Diode * Component::createDiode( ECNode *n0, ECNode *n1 ) +{ return createDiode( n0->pin(), n1->pin() ); } +Inductance * Component::createInductance( ECNode *n0, ECNode *n1, double inductance ) +{ return createInductance( n0->pin(), n1->pin(), inductance ); } +LogicIn * Component::createLogicIn( ECNode *node ) +{ return createLogicIn( node->pin() ); } +LogicOut * Component::createLogicOut( ECNode *node, bool isHigh ) +{ return createLogicOut( node->pin(), isHigh ); } +OpAmp * Component::createOpAmp( ECNode * nonInverting, ECNode * out, ECNode * inverting ) +{ return createOpAmp( nonInverting->pin(), out->pin(), inverting->pin() ); } +Resistance * Component::createResistance( ECNode *n0, ECNode *n1, double resistance ) +{ return createResistance( n0->pin(), n1->pin(), resistance ); } +Switch * Component::createSwitch( ECNode *n0, ECNode *n1, bool open ) +{ return createSwitch( n0->pin(), n1->pin(), open ); } +VCCS * Component::createVCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createVCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +VCVS * Component::createVCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createVCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +VoltagePoint * Component::createVoltagePoint( ECNode *n0, double voltage ) +{ return createVoltagePoint( n0->pin(), voltage ); } +VoltageSignal * Component::createVoltageSignal( ECNode *n0, ECNode *n1, double voltage ) +{ return createVoltageSignal( n0->pin(), n1->pin(), voltage ); } +VoltageSource * Component::createVoltageSource( ECNode *n0, ECNode *n1, double voltage ) +{ return createVoltageSource( n0->pin(), n1->pin(), voltage ); } + +BJT* Component::createBJT( Pin *cN, Pin *bN, Pin *eN, bool isNPN ) +{ + BJT *e = new BJT(isNPN); + + QValueList pins; + pins << bN << cN << eN; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Capacitance* Component::createCapacitance( Pin *n0, Pin *n1, double capacitance ) +{ + Capacitance *e = new Capacitance( capacitance, 1./LINEAR_UPDATE_RATE ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CCCS* Component::createCCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + CCCS *e = new CCCS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CCVS* Component::createCCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + CCVS *e = new CCVS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterCircuitDependent( it, pins ); + + pins.clear(); + pins << n0 << n1; + setInterGroundDependent( it, pins ); + + pins.clear(); + pins << n2 << n3; + setInterGroundDependent( it, pins ); + + return e; +} + +CurrentSignal* Component::createCurrentSignal( Pin *n0, Pin *n1, double current ) +{ + CurrentSignal *e = new CurrentSignal( 1./LINEAR_UPDATE_RATE, current ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CurrentSource* Component::createCurrentSource( Pin *n0, Pin *n1, double current ) +{ + CurrentSource *e = new CurrentSource(current); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Diode* Component::createDiode( Pin *n0, Pin *n1 ) +{ + Diode *e = new Diode(); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Inductance* Component::createInductance( Pin *n0, Pin *n1, double inductance ) +{ + Inductance *e = new Inductance( inductance, 1./LINEAR_UPDATE_RATE ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +LogicIn *Component::createLogicIn( Pin *node ) +{ + LogicIn *e = new LogicIn(LogicIn::getConfig()); + + QValueList pins; + pins << node; + + ElementMapList::iterator it = handleElement( e, pins ); + return e; +} + +LogicOut *Component::createLogicOut( Pin *node, bool isHigh ) +{ + LogicOut *e = new LogicOut( LogicIn::getConfig(), isHigh); + + QValueList pins; + pins << node; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +OpAmp * Component::createOpAmp( Pin * nonInverting, Pin * inverting, Pin * out ) +{ + OpAmp * e = new OpAmp(); + + QValueList pins; + pins << nonInverting << inverting << out; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Resistance* Component::createResistance( Pin *n0, Pin *n1, double resistance ) +{ + Resistance *e = new Resistance(resistance); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Switch* Component::createSwitch( Pin *n0, Pin *n1, bool open ) +{ + // Note that a Switch is not really an element (although in many cases it + // behaves very much like one). + + Switch * e = new Switch( this, n0, n1, open ? Switch::Open : Switch::Closed ); + m_switchList.append(e); + n0->addSwitch( e ); + n1->addSwitch( e ); + emit switchCreated( e ); + return e; +} + +VCCS* Component::createVCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + VCCS *e = new VCCS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VCVS* Component::createVCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + VCVS *e = new VCVS(gain); + + QValueList pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterCircuitDependent( it, pins ); + + pins.clear(); + pins << n0 << n1; + setInterGroundDependent( it, pins ); + + pins.clear(); + pins << n2 << n3; + setInterGroundDependent( it, pins ); + return e; +} + +VoltagePoint* Component::createVoltagePoint( Pin *n0, double voltage ) +{ + VoltagePoint *e = new VoltagePoint(voltage); + + QValueList pins; + pins << n0; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VoltageSignal* Component::createVoltageSignal( Pin *n0, Pin *n1, double voltage ) +{ + VoltageSignal *e = new VoltageSignal( 1./LINEAR_UPDATE_RATE, voltage ); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VoltageSource* Component::createVoltageSource( Pin *n0, Pin *n1, double voltage ) +{ + VoltageSource *e = new VoltageSource(voltage); + + QValueList pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + + +ElementMapList::iterator Component::handleElement( Element *e, const QValueList & pins ) +{ + if (!e) + return m_elementMapList.end(); + + ElementMap em; + em.e = e; + int at = 0; + QValueList::ConstIterator end = pins.end(); + for ( QValueList::ConstIterator it = pins.begin(); it != end; ++it ) + { + (*it)->addElement(e); + em.n[at++] = *it; + } + + ElementMapList::iterator it = m_elementMapList.append(em); + + emit elementCreated(e); + return it; +} + + +void Component::setInterDependent( ElementMapList::iterator it, const QValueList & pins ) +{ + setInterCircuitDependent( it, pins ); + setInterGroundDependent( it, pins ); +} + + +void Component::setInterCircuitDependent( ElementMapList::iterator it, const QValueList & pins ) +{ + QValueList::ConstIterator end = pins.end(); + for ( QValueList::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) + { + for ( QValueList::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) + { + (*it1)->addCircuitDependentPin( *it2 ); + } + } + + (*it).interCircuitDependent.append( pins ); +} + + +void Component::setInterGroundDependent( ElementMapList::iterator it, const QValueList & pins ) +{ + QValueList::ConstIterator end = pins.end(); + for ( QValueList::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) + { + for ( QValueList::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) + { + (*it1)->addGroundDependentPin( *it2 ); + } + } + + (*it).interGroundDependent.append( pins ); +} + + +void Component::rebuildPinInterDepedence() +{ + setAllPinsInterIndependent(); + + // Rebuild dependencies + ElementMapList::iterator emlEnd = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != emlEnd; ++it ) + { + // Many copies of the pin lists as these will be affected when we call setInter*Dependent + PinListList list = (*it).interCircuitDependent; + + PinListList::iterator depEnd = list.end(); + for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) + setInterCircuitDependent( it, *depIt ); + + list = (*it).interGroundDependent; + + depEnd = list.end(); + for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) + setInterGroundDependent( it, *depIt ); + } +} + + +void Component::setAllPinsInterIndependent() +{ + NodeMap::iterator nmEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nmEnd; ++it ) + { + PinVector pins = (static_cast(it.data().node))->pins(); + PinVector::iterator pinsEnd = pins.end(); + for ( PinVector::iterator pinsIt = pins.begin(); pinsIt != pinsEnd; ++pinsIt ) + { + if ( *pinsIt ) + (*pinsIt)->removeDependentPins(); + } + } +} + + +void Component::initElements( const uint stage ) +{ + /// @todo this function is ugly and messy and needs tidying up + + const ElementMapList::iterator end = m_elementMapList.end(); + + if ( stage == 1 ) + { + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + (*it).e->add_initial_dc(); + } + return; + } + + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + ElementMap m = (*it); + + if ( m.n[3] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId(), m.n[3]->eqId() ); + } + else if ( m.n[2] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId() ); + } + else if ( m.n[1] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId() ); + } + else if ( m.n[0] ) { + m.e->setCNodes( m.n[0]->eqId() ); + } + } + + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + (*it).e->add_map(); + } +} + + +ECNode * Component::createPin( double x, double y, int orientation, const QString & name ) +{ + return dynamic_cast( createNode( x, y, orientation, name, Node::ec_pin ) ); +} + + +//BEGIN class ElementMap +ElementMap::ElementMap() +{ + e = 0; + for ( int i = 0; i < 4; ++i ) + n[i] = 0; +} +//END class ElementMap + + +#include "component.moc" + + diff --git a/src/electronics/component.h b/src/electronics/component.h new file mode 100644 index 0000000..d45d835 --- /dev/null +++ b/src/electronics/component.h @@ -0,0 +1,362 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef COMPONENT_H +#define COMPONENT_H + +#include "cnitem.h" + +#include + +class ICNDocument; +class CircuitDocument; +class ECNode; +class ECSubcircuit; +class Element; +class Node; +class Pin; + +class BJT; +class Capacitance; +class CCCS; +class CCVS; +class CurrentSignal; +class CurrentSource; +class Diode; +class Inductance; +class LogicIn; +class LogicOut; +class OpAmp; +class Resistance; +class Switch; +class Transformer; +class VCCS; +class VCVS; +class VoltagePoint; +class VoltageSignal; +class VoltageSource; + +typedef QValueList ECNodeList; +typedef QValueList ElementList; +typedef QValueList SwitchList; + +typedef QValueList< QValueList > PinListList; + +/** +Contains vital information about the elements in the component. +*/ +class ElementMap +{ + public: + ElementMap(); + + Element * e; // The element + Pin * n[4]; // The Pins associated with the CNodes in the element + + /// @see Component::setInterCircuitDependent + PinListList interCircuitDependent; + + /// @see Component::setInterGroundDependent + PinListList interGroundDependent; +}; + +typedef QValueList ElementMapList; + +/** +@short Bass class for all electrical components +@author David Saxton +*/ +class Component : public CNItem +{ + Q_OBJECT + public: + Component( ICNDocument *icnDocument, bool newItem, const QString &id ); + virtual ~Component(); + + ECNode* createPin( double _x, double _y, int orientation, const QString &name ); + /** + * Reinherit this function to disallow rotation of the component. + */ + virtual bool canRotate() const { return true; } + /** + * Angle of orientation + */ + int angleDegrees() const { return m_angleDegrees; } + /** + * Sets the angle (in degrees) + */ + void setAngleDegrees( int degrees ); + /** + * Whether or not the item is flipped + */ + bool flipped() const { return b_flipped; } + /** + * Sets whether or not the item is flipped + */ + void setFlipped( bool flipped ); + /** + * After calculating nodal voltages, each component will be + * called to tell its nodes what the current flowing *into* + * the component is. + */ + void setNodalCurrents(); + /** + * @return pointer to the CircuitDocument that we're in. + */ + CircuitDocument * circuitDocument() const { return m_pCircuitDocument; } + void initElements( const uint stage ); + virtual void finishedCreation(); + /** + * If reinherit (and use) the stepNonLogic function, then you must also + * reinherit this function so that it returns true. Else your component + * will not get called. + */ + virtual bool doesStepNonLogic() const { return false; } + virtual void stepNonLogic() {}; + /** + * Returns the translation matrix used for painting et al + * @param orientation The orientation to use + * @param x x co-ordinate of the center of the object to be mapped + * @param y y co-ordinate of the center of the object to be mapped + * @param inverse If false, maps the unrotated item to a rotated one, else mapped->unmapped + */ + static QWMatrix transMatrix( int angleDegrees, bool flipped, int x, int y, bool inverse = false ); + /** + * @return Information about the component in an ItemData struct. + */ + virtual ItemData itemData() const; + /** + * Restores the state of the component from the ItemData struct. + */ + virtual void restoreFromItemData( const ItemData &itemData ); + + BJT * createBJT( Pin *c, Pin *b, Pin *e, bool isNPN = true ); + BJT * createBJT( ECNode *c, ECNode *b, ECNode *e, bool isNPN = true ); + + Capacitance * createCapacitance( Pin *n0, Pin *n1, double capacitance ); + Capacitance * createCapacitance( ECNode *n0, ECNode *n1, double capacitance ); + + CCCS * createCCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + CCCS * createCCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + CCVS * createCCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + CCVS * createCCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + CurrentSignal * createCurrentSignal( Pin *n0, Pin *n1, double current ); + CurrentSignal * createCurrentSignal( ECNode *n0, ECNode *n1, double current ); + + CurrentSource * createCurrentSource( Pin *n0, Pin *n1, double current ); + CurrentSource * createCurrentSource( ECNode *n0, ECNode *n1, double current ); + + Diode * createDiode( Pin *n0, Pin *n1 ); + Diode * createDiode( ECNode *n0, ECNode *n1 ); + + Inductance * createInductance( Pin *n0, Pin *n1, double inductance ); + Inductance * createInductance( ECNode *n0, ECNode *n1, double inductance ); + + LogicIn * createLogicIn( Pin *node ); + LogicIn * createLogicIn( ECNode *node ); + + LogicOut * createLogicOut( Pin *node, bool isHigh ); + LogicOut * createLogicOut( ECNode *node, bool isHigh ); + + OpAmp * createOpAmp( Pin * nonInverting, Pin * out, Pin * inverting ); + OpAmp * createOpAmp( ECNode * nonInverting, ECNode * out, ECNode * inverting ); + + Resistance * createResistance( Pin *n0, Pin *n1, double resistance ); + Resistance * createResistance( ECNode *n0, ECNode *n1, double resistance ); + + Switch * createSwitch( Pin *n0, Pin *n1, bool open ); + Switch * createSwitch( ECNode *n0, ECNode *n1, bool open ); + + VCCS * createVCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + VCCS * createVCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + VCVS * createVCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ); + VCVS * createVCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ); + + VoltagePoint * createVoltagePoint( Pin *n0, double voltage ); + VoltagePoint * createVoltagePoint( ECNode *n0, double voltage ); + + VoltageSignal * createVoltageSignal( Pin *n0, Pin *n1, double voltage ); + VoltageSignal * createVoltageSignal( ECNode *n0, ECNode *n1, double voltage ); + + VoltageSource * createVoltageSource( Pin *n0, Pin *n1, double voltage ); + VoltageSource * createVoltageSource( ECNode *n0, ECNode *n1, double voltage ); + + + ECNode* ecNodeWithID( const QString &ecNodeId ); + + /** + * Safely delete an element - in this case, calls element->componentDeleted, + * and removes it from the element list. + * @param setPinsInterIndependent whether to call + * setPinsInterIndependent. The call is time-consuming, and unnecessary + * if the pins from which the element was originally attached will be/ + * were removed, or they will become interdependent again. + */ + void removeElement( Element * element, bool setPinsInterIndependent ); + /** + * Safely remove a switch. + */ + void removeSwitch( Switch * sw ); + /** + * Removes all elements and switches. + * @param setPinsInterIndependent whether to bother calling + * setPinsInterIndependent. This is false when calling from the + * destructor, or when the dependency information is the same. + */ + void removeElements( bool setPinsInterIndependent = false ); + /** + * @return the list of switches that this component uses. + */ + SwitchList switchList() const { return m_switchList; } + + signals: + /** + * Emitted when an element is created. + */ + void elementCreated( Element * element ); + /** + * Emitted when an element is destroyed. + */ + void elementDestroyed( Element * element ); + /** + * Emitted when a switch. is created + */ + void switchCreated( Switch * sw ); + /** + * Emitted when a switch is destroyed. + */ + void switchDestroyed( Switch * sw ); + + public slots: + virtual void slotUpdateConfiguration(); + virtual void removeItem(); + + protected: + /** + * Convenience functionality provided for components in a port shape + * (such as ParallelPortComponent and SerialPortComponent). + */ + void drawPortShape( QPainter & p ); + virtual void itemPointsChanged(); + virtual void updateAttachedPositioning(); + virtual void initPainter( QPainter &p ); + /** + * Untranforms the painter from the matrix. This *must* be called after doing + * initPainter( QPainter &p ); + */ + virtual void deinitPainter( QPainter &p ); + /** + * This creates a set of nodes with their internal IDs set to those in QStringList pins. + * The pins are in a DIP arrangement, and are spaced width() apart. + */ + void initDIP( const QStringList & pins ); + /** + * Creates the DIP symbol: + * @li constructs rectangular shape + * @li puts on text labels in appropriate positions from QStringList pins + */ + void initDIPSymbol( const QStringList & pins, int width ); + /** + * Create 1 pin on the left of the component, placed half way down if h1 is + * -1 - else at the position of h1. + */ + void init1PinLeft( int h1 = -1 ); + /** + * Create 2 pins on the left of the component, either spread out, or at the + * given heights. + */ + void init2PinLeft( int h1 = -1, int h2 = -1 ); + /** + * Create 3 pins on the left of the component, either spread out, or at the + * given heights. + */ + void init3PinLeft( int h1 = -1, int h2 = -1, int h3 = -1 ); + /** + * Create 4 pins on the left of the component, either spread out, or at the + * given heights. + */ + void init4PinLeft( int h1 = -1, int h2 = -1, int h3 = -1, int h4 = -1 ); + /** + * Create 1 pin on the right of the component, placed half way down if h1 is + * -1 - else at the position of h1. + */ + void init1PinRight( int h1 = -1 ); + /** + * Create 2 pins on the right of the component, either spread out, or at the + * given heights. + */ + void init2PinRight( int h1 = -1, int h2 = -1 ); + /** + * Create 3 pins on the right of the component, either spread out, or at the + * given heights. + */ + void init3PinRight( int h1 = -1, int h2 = -1, int h3 = -1 ); + /** + * Create 4 pins on the right of the component, either spread out, or at the + * given heights. + */ + void init4PinRight( int h1 = -1, int h2 = -1, int h3 = -1, int h4 = -1 ); + /** + * When we remove an element, we have to rebuild the list of inter-dependent + * nodes. (when adding elements, we just call setInterDependent). + */ + void rebuildPinInterDepedence(); + + // Pointers to commonly used nodes + ECNode * m_pPNode[4]; + ECNode * m_pNNode[4]; + + QGuardedPtr m_pCircuitDocument; + int m_angleDegrees; + bool b_flipped; + + private: + /** + * Convenience function for calling both setInterCircuitDependent and + * setInterGroundDependent. + * @param it Which pins are inter-dependent needs to be recorded in case + * this information is later needed in rebuildPinInterDependence. + */ + void setInterDependent( ElementMapList::iterator it, const QValueList & pins ); + /** + * Sets all pins independent of each other. + */ + void setAllPinsInterIndependent(); + /** + * The given pins will affect the simulation of each other. Therefore, they + * will need to be simulated in the same circuit. + */ + void setInterCircuitDependent( ElementMapList::iterator it, const QValueList & pins ); + /** + * If any of the given pins are ground, then that will affect whether + * any of the other pins can be ground. + */ + void setInterGroundDependent( ElementMapList::iterator it, const QValueList & pins ); + /** + * List of ElementMaps; which contain information on the pins associated + * with the element as well as the dependence between the pins for that + * element. + * @see ElementMap + */ + ElementMapList m_elementMapList; + /** + * The switches used by the component. + */ + SwitchList m_switchList; + /** + * @return an iterator to the element in m_elementMapList + */ + ElementMapList::iterator handleElement( Element *e, const QValueList & pins ); +}; + +#endif diff --git a/src/electronics/components/Makefile.am b/src/electronics/components/Makefile.am new file mode 100644 index 0000000..c388cf6 --- /dev/null +++ b/src/electronics/components/Makefile.am @@ -0,0 +1,33 @@ +INCLUDES = -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \ + -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \ + -I$(top_srcdir)/src/micro $(glib_cflags) $(all_includes) + +METASOURCES = AUTO +noinst_HEADERS = ecresistor.h ecled.h ecdiode.h ecsevensegment.h eckeypad.h \ + eccapacitor.h ec555.h eccurrentsource.h ecfixedvoltage.h ecbcdto7segment.h \ + ecsignallamp.h ecclockinput.h ecpotentiometer.h ecopamp.h ecvoltagesource.h \ + eccurrentsignal.h ecvoltagesignal.h ecground.h multiinputgate.h fulladder.h multiplexer.h \ + demultiplexer.h externalconnection.h ecsubcircuit.h meter.h probe.h resistordip.h \ + addac.h dependentsource.h flipflop.h toggleswitch.h pushswitch.h ram.h \ + discretelogic.h piccomponent.h piccomponentpin.h binarycounter.h bidirled.h \ + matrixdisplay.h bussplitter.h matrixdisplaydriver.h magnitudecomparator.h \ + serialportcomponent.h parallelportcomponent.h inductor.h ecbjt.h rotoswitch.h + +noinst_LTLIBRARIES = libcomponents.la +libcomponents_la_SOURCES = ecresistor.cpp ecled.cpp ecdiode.cpp \ + ecsevensegment.cpp eckeypad.cpp eccapacitor.cpp ec555.cpp eccurrentsource.cpp \ + ecfixedvoltage.cpp ecbcdto7segment.cpp ecsignallamp.cpp ecclockinput.cpp \ + ecpotentiometer.cpp ecopamp.cpp ecvoltagesource.cpp eccurrentsignal.cpp ecvoltagesignal.cpp \ + ecground.cpp multiinputgate.cpp fulladder.cpp multiplexer.cpp demultiplexer.cpp \ + externalconnection.cpp ecsubcircuit.cpp meter.cpp probe.cpp resistordip.cpp addac.cpp \ + dependentsource.cpp flipflop.cpp toggleswitch.cpp pushswitch.cpp ram.cpp discretelogic.cpp \ + piccomponent.cpp piccomponentpin.cpp binarycounter.cpp bidirled.cpp matrixdisplay.cpp \ + bussplitter.cpp matrixdisplaydriver.cpp magnitudecomparator.cpp serialportcomponent.cpp \ + parallelportcomponent.cpp inductor.cpp ecbjt.cpp rotoswitch.cpp + +libcomponents_la_PCH = AUTO + + +libcomponents_la_LIBADD =\ + $(top_builddir)/src/electronics/simulation/libelements.la diff --git a/src/electronics/components/addac.cpp b/src/electronics/components/addac.cpp new file mode 100644 index 0000000..a58e2d8 --- /dev/null +++ b/src/electronics/components/addac.cpp @@ -0,0 +1,281 @@ +/*************************************************************************** + * 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 "addac.h" +#include "ecnode.h" +#include "logic.h" +#include "libraryitem.h" +#include "pin.h" +#include "voltagepoint.h" + +#include +#include +#include + + +Item* ADC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ADC( (ICNDocument*)itemDocument, newItem, id ); +} + + +Item* DAC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new DAC( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ADC::libraryItem() +{ + return new LibraryItem( + "ec/adc", + i18n("Analog-Digital"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + ADC::construct + ); +} + + +LibraryItem* DAC::libraryItem() +{ + return new LibraryItem( + "ec/dac", + i18n("Digital-Analog"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + DAC::construct + ); +} + + +//BEGIN class ADDAC +ADDAC::ADDAC( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + m_numBits = 0; + m_range = 0; + + createProperty( "numBits", Variant::Type::Int ); + property("numBits")->setCaption( i18n("Number Bits") ); + property("numBits")->setMinValue(2); + property("numBits")->setMaxValue(max_ADDAC_bits); + property("numBits")->setValue(2); + + createProperty( "range", Variant::Type::Double ); + property("range")->setCaption( i18n("Input Range") ); + property("range")->setUnit("V"); + property("range")->setMinValue(-1e12); + property("range")->setMaxValue(1e12); + property("range")->setValue(5); +} + +ADDAC::~ADDAC() +{ +} + + +void ADDAC::dataChanged() +{ + m_range = dataDouble("range"); + initPins(); +} + +//END class ADDAC + + + + +//BEGIN class ADC +ADC::ADC( ICNDocument *icnDocument, bool newItem, const char *id ) + : ADDAC( icnDocument, newItem, (id) ? id : "adc" ) +{ + m_name = i18n("ADC"); + m_desc = i18n("Converts an analog signal into a digital output."); + + for ( int i=0; ipin()->voltage() * (std::pow( 2, double(m_numBits) )-1.) / m_range; + double roundBitValue = std::floor( floatBitValue+0.5 ); + + if ( roundBitValue < 0 ) + { + for ( int i = 0; isetHigh(false); + return; + } + + uint roundedBitValue = uint(roundBitValue); + for ( int i = 0; isetHigh( roundedBitValue & ( 1 << i ) ); +} + + +void ADC::initPins() +{ + int numBits = dataInt("numBits"); + + if ( numBits < 2 ) + numBits = 2; + else if ( numBits > max_ADDAC_bits ) + numBits = max_ADDAC_bits; + + if ( numBits == m_numBits ) + return; + + QStringList pins; + + int inPos = (numBits-1+(numBits%2))/2; + for ( int i=0; i=0; --i ) + pins += QString::number(i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if (!m_realNode) + m_realNode = ecNodeWithID("In"); + + + if ( numBits > m_numBits ) + { + for ( int i=m_numBits; iisHigh() ? 1 : 0 ) << i; + +// double valueAsDouble = double(value); +// double powChange = std::pow( double(m_numBits), 2 )-1.; +// m_voltagePoint->setVoltage( m_range * valueAsDouble / powChange ); + m_voltagePoint->setVoltage( m_range * double(value) / (std::pow( 2, double(m_numBits) )-1.) ); +} + + +void DAC::initPins() +{ + int numBits = dataInt("numBits"); + + if ( numBits < 2 ) + numBits = 2; + else if ( numBits > max_ADDAC_bits ) + numBits = max_ADDAC_bits; + + if ( numBits == m_numBits ) + return; + + QStringList pins; + + for ( int i=0; i=inPos; --i ) + pins += ""; + + pins += "Out"; + + for ( int i=inPos-2; i>=0; --i ) + pins += ""; + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if (!m_voltagePoint) + m_voltagePoint = createVoltagePoint( ecNodeWithID("Out"), 0. ); + + if ( numBits > m_numBits ) + { + for ( int i=m_numBits; i +#include + +Item* BiDirLED::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BiDirLED( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* BiDirLED::libraryItem() +{ + return new LibraryItem ( + "ec/bidir_led", + i18n("Bidirectional LED"), + i18n("Outputs"), + "bidirled.png", + LibraryItem::lit_component, + BiDirLED::construct + ); +} + +BiDirLED::BiDirLED( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "bidir_led" ) +{ + m_name = i18n("Bidirectional LED"); + m_desc = i18n("Bidrectional Light Emitting Diode"); + m_bDynamicContent = true; + + setSize( -8, -16, 16, 32 ); + init1PinLeft(); + init1PinRight(); + setSize( -8, -24, 24, 40 ); + + m_pDiode[0] = createDiode( m_pNNode[0], m_pPNode[0] ); + m_pDiode[1] = createDiode( m_pPNode[0], m_pNNode[0] ); + + avg_brightness[0] = avg_brightness[1] = 255; + lastUpdatePeriod = 0.; + r[0]=r[1]=g[0]=g[1]=b[0]=b[1]=0; + last_brightness[0] = last_brightness[1] = 255; + + createProperty( "0-color1", Variant::Type::Color ); + property("0-color1")->setCaption( i18n("Color 1") ); + property("0-color1")->setColorScheme( ColorCombo::LED ); + + createProperty( "0-color2", Variant::Type::Color ); + property("0-color2")->setCaption( i18n("Colour 2") ); + property("0-color2")->setColorScheme( ColorCombo::LED ); +} + +BiDirLED::~BiDirLED() +{ +} + +void BiDirLED::dataChanged() +{ + QString colors[] = { "0-color1", "0-color2" }; + for ( unsigned i = 0; i < 2; i++ ) + { + QColor color = dataColor(colors[i]); + r[i] = color.red(); + g[i] = color.green(); + b[i] = color.blue(); + r[i] /= 0x100; + g[i] /= 0x100; + b[i] /= 0x100; + } +} + +void BiDirLED::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + lastUpdatePeriod += interval; + + for ( unsigned i = 0; i < 2; i++ ) + avg_brightness[i] += ECLed::brightness(m_pDiode[i]->current())*interval; +} + +void BiDirLED::drawShape( QPainter &p ) +{ + initPainter(p); + + for ( unsigned i = 0; i < 2; i++ ) + { + uint _b; + if ( lastUpdatePeriod == 0. ) + _b = last_brightness[i]; + + else + { + _b = uint(avg_brightness[i]/lastUpdatePeriod); + last_brightness[i] = _b; + } + avg_brightness[i] = 0.; + + p.setBrush( QColor( uint(255-(255-_b)*(1-r[i])), uint(255-(255-_b)*(1-g[i])), uint(255-(255-_b)*(1-b[i])) ) ); + + + QPointArray pa(3); + if ( i == 0 ) + { + pa[0] = QPoint( 8, -8 ); + pa[1] = QPoint( -8, -16 ); + pa[2] = QPoint( -8, 0 ); + } + else + { + pa[0] = QPoint( -8, 8 ); + pa[1] = QPoint( 8, 0 ); + pa[2] = QPoint( 8, 16 ); + } + + pa.translate( int(x()), int(y()) ); + p.drawPolygon(pa); + p.drawPolyline(pa); + } + lastUpdatePeriod = 0.; + + // Draw the arrows indicating it's a LED + int _x = (int)x()-2; + int _y = (int)y()-21; + + p.drawLine( _x+9, _y+3, _x+12, _y ); // Tail of left arrow + p.drawLine( _x+12, _y, _x+10, _y ); // Left edge of left arrow tip + p.drawLine( _x+12, _y, _x+12, _y+2 ); // Right edge of left arrow tip + + p.drawLine( _x+12, _y+6, _x+15, _y+3 ); // Tail of right arrow + p.drawLine( _x+15, _y+3, _x+13, _y+3 ); // Left edge of right arrow tip + p.drawLine( _x+15, _y+3, _x+15, _y+5 ); // Right edge of right arrow tip + + p.drawLine( _x+10, _y, _x+15, _y+5 ); // Diagonal line that forms base of both arrow tips + + _x = int(x()); + _y = int(y()); + p.drawLine( _x+8, _y-16, _x+8, _y ); + p.drawLine( _x-8, _y, _x-8, _y+16 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/bidirled.h b/src/electronics/components/bidirled.h new file mode 100644 index 0000000..e80f4e0 --- /dev/null +++ b/src/electronics/components/bidirled.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef BIDIRLED_H +#define BIDIRLED_H + +#include + +/** +@author David Saxton +*/ +class BiDirLED : public Component +{ + public: + BiDirLED( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + ~BiDirLED(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void dataChanged(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + private: + virtual void drawShape( QPainter &p ); + + double r[2]; + double g[2]; + double b[2]; + + double avg_brightness[2]; + uint last_brightness[2]; + double lastUpdatePeriod; + Diode *m_pDiode[2]; +}; + +#endif diff --git a/src/electronics/components/binarycounter.cpp b/src/electronics/components/binarycounter.cpp new file mode 100644 index 0000000..f278104 --- /dev/null +++ b/src/electronics/components/binarycounter.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "binarycounter.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +Item* BinaryCounter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BinaryCounter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* BinaryCounter::libraryItem() +{ + QStringList ids; + ids << "ec/binary_counter" << "ec/4_bit_binary_counter"; + return new LibraryItem( + ids, + i18n("Binary Counter"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + BinaryCounter::construct + ); +} + +BinaryCounter::BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "binary_counter" ) +{ + m_name = i18n("Binary Counter"); + m_desc = i18n("Holds an internal count, which changes when the clock input > pin is pulsed.

" + "Normal operation: en (Enable) and u/d (Up/Down) are held high, r (Reset) is low."); + + enLogic = inLogic = rLogic = udLogic = 0L; + + b_reset = false; + b_triggerHigh = true; + b_oldIn = false; + m_value = 0; + b_en = false; + b_ud = false; + m_numBits = 0; + m_maxValue = false; + m_bDoneLogicIn = false; + + createProperty( "trig", Variant::Type::Select ); + property("trig")->setCaption( i18n("Trigger Edge") ); + property("trig")->setAllowed( QStringList::split( ',', "Rising,Falling" ) ); + property("trig")->setValue("Rising"); + + createProperty( "bitcount", Variant::Type::Int ); + property("bitcount")->setCaption( i18n("Bit Count") ); + property("bitcount")->setMinValue(1); + property("bitcount")->setMaxValue(26); + property("bitcount")->setValue(4); +} + + +BinaryCounter::~BinaryCounter() +{ +} + + +void BinaryCounter::dataChanged() +{ + initPins( dataInt("bitcount") ); + + b_triggerHigh = dataString("trig") == "Rising"; + setDisplayText( ">", b_triggerHigh ? "^>" : "_>" ); +} + + +void BinaryCounter::initPins( unsigned numBits ) +{ + if ( m_numBits == numBits ) + return; + + QStringList pins; + pins << "en" << ">" << "u/d" << "r"; + + for ( int i = 0; i < QABS(4-int(numBits)); i++ ) + pins << ""; + + for ( int i = numBits-1; i >= 0; i-- ) + pins << QChar('A'+i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + if ( m_numBits < numBits ) + { + for ( unsigned i = m_numBits; i < numBits; i++ ) + m_pLogicOut[i] = createLogicOut( ecNodeWithID( QChar('A'+i) ), false ); + } + else + { + for ( unsigned i = numBits; i < m_numBits; i++ ) + { + QString id = QChar('A'+i); + removeElement( m_pLogicOut[i], false ); + removeDisplayText(id); + removeNode(id); + } + } + + m_numBits = numBits; + m_maxValue = (1<") ); + rLogic = createLogicIn( ecNodeWithID("r") ); + udLogic = createLogicIn( ecNodeWithID("u/d") ); + + enLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::enStateChanged) ); + inLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::inStateChanged) ); + rLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::rStateChanged) ); + udLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::udStateChanged) ); + + m_bDoneLogicIn = true; + } + + outputValue(); +} + + +void BinaryCounter::inStateChanged( bool state ) +{ + if ( (state != b_oldIn) && b_en && !b_reset && state == b_triggerHigh ) + { + m_value += (b_ud) ? 1 : -1; + + if ( m_value < 0 ) + m_value = m_maxValue; + + else if ( m_value > m_maxValue ) + m_value = 0; + + outputValue(); + } + + b_oldIn = state; +} + + +void BinaryCounter::rStateChanged( bool state ) +{ + b_reset = state; + if (b_reset) + { + m_value = 0; + outputValue(); + } +} + + +void BinaryCounter::enStateChanged( bool state ) +{ + b_en = state; +} + + +void BinaryCounter::udStateChanged( bool state ) +{ + b_ud = state; +} + + +void BinaryCounter::outputValue() +{ + for ( unsigned i = 0; i < m_numBits; i++ ) + m_pLogicOut[i]->setHigh( m_value & (1 << i) ); +} + diff --git a/src/electronics/components/binarycounter.h b/src/electronics/components/binarycounter.h new file mode 100644 index 0000000..b15762d --- /dev/null +++ b/src/electronics/components/binarycounter.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef EC4BITCOUNTER_H +#define EC4BITCOUNTER_H + +#include "component.h" +#include "logic.h" + +/** +Simple logic counter. 4 Inputs, 4 Outputs. + +Outputs (A-D) represent the stored value (0-15). +The inputs are: +@li en - Enable incrementing of value +@li in - Input (trigger high) +@li r - Reset stored value to 0 +@li ud - Up/Down increment + +@short 4 Bit Binary Counter +@author David Saxton +*/ +class BinaryCounter : public CallbackClass, public Component +{ +public: + BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~BinaryCounter(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool state ); // Input + void rStateChanged( bool state ); // Reset + void enStateChanged( bool state ); // Enable + void udStateChanged( bool state ); // Up/Down + void outputValue(); + void dataChanged(); + void initPins( unsigned numBits ); + + LogicIn *enLogic, *inLogic, *rLogic, *udLogic; + LogicOut * m_pLogicOut[26]; + + unsigned m_numBits; + bool b_triggerHigh; + bool b_en; // Enable + bool b_ud; // Up/Down + bool b_oldIn; + bool b_reset; + long m_value; + long m_maxValue; + bool m_bDoneLogicIn; +}; + +#endif diff --git a/src/electronics/components/bussplitter.cpp b/src/electronics/components/bussplitter.cpp new file mode 100644 index 0000000..62fbb39 --- /dev/null +++ b/src/electronics/components/bussplitter.cpp @@ -0,0 +1,133 @@ +/*************************************************************************** + * 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 "bussplitter.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "wire.h" + +#include +#include + +Item* BusSplitter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new BusSplitter( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* BusSplitter::libraryItem() +{ + return new LibraryItem( + "ec/bus", + i18n("Bus"), + i18n("Connections"), + "bus.png", + LibraryItem::lit_component, + BusSplitter::construct ); +} + + +const unsigned MAX_BUS_SIZE = 10000; + + +BusSplitter::BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "Bus" ) +{ + m_name = i18n("Bus Splitter"); + m_desc = i18n("Merges several connections into one."); + + m_busSize = 0; + init1PinLeft(); + m_pInNode = m_pNNode[0]; + + createProperty( "size", Variant::Type::Int ); + property("size")->setCaption( i18n("Size") ); + property("size")->setMinValue(1); + property("size")->setMaxValue(MAX_BUS_SIZE); + property("size")->setValue(8); +} + + +BusSplitter::~BusSplitter() +{ +} + + +void BusSplitter::dataChanged() +{ + unsigned busSize = dataInt("size"); + + if ( busSize < 1 ) + busSize = 1; + + else if ( busSize > MAX_BUS_SIZE ) + busSize = MAX_BUS_SIZE; + + if ( busSize == m_busSize ) + return; + + m_pInNode->setNumPins(busSize); + + if ( busSize > m_busSize ) + { + m_pWires.resize(busSize); + for ( unsigned i = m_busSize; i < unsigned(busSize); i++ ) + { + Pin * pin = createPin( 16, 0, 180, outNodeID(i) )->pin(); + m_pWires[i] = new Wire( m_pInNode->pin(i), pin ); + } + } + else + { + for ( unsigned i = busSize; i < unsigned(m_busSize); i++ ) + { + removeNode( outNodeID(i) ); + delete m_pWires[i]; + } + m_pWires.resize(busSize); + } + m_busSize = busSize; + + // Position pins + setSize( 0, -int(m_busSize+1)*8, 8, int(m_busSize+1)*16, true ); + for ( int i = 0; i < int(m_busSize); i++ ) + m_nodeMap[ outNodeID(i) ].y = 16*i - int(m_busSize+1)*8 + 24; + m_nodeMap["n1"].y = -int(m_busSize+1)*8 + 8; + + updateAttachedPositioning(); +} + + +QString BusSplitter::outNodeID( unsigned node ) const +{ + return QString("out_%1").arg(QString::number(node)); +} + + +void BusSplitter::drawShape( QPainter &p ) +{ + initPainter(p); + +// QPen pen(p.pen()); +// pen.setWidth(); +// p.setPen(pen); + + int _x = int(x()); + int _y = int(y()); + + QRect r = m_sizeRect; + r.moveBy( _x, _y ); + p.drawRect(r); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/bussplitter.h b/src/electronics/components/bussplitter.h new file mode 100644 index 0000000..ccd1994 --- /dev/null +++ b/src/electronics/components/bussplitter.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef BUSSPLITTER_H +#define BUSSPLITTER_H + +#include + +#include +#include + +class Wire; + +/** +@author David Saxton +*/ +class BusSplitter : public Component +{ + public: + BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~BusSplitter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + + protected: + QString outNodeID( unsigned node ) const; + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + unsigned m_busSize; + QValueVector > m_pWires; + ECNode * m_pInNode; +}; + +#endif diff --git a/src/electronics/components/demultiplexer.cpp b/src/electronics/components/demultiplexer.cpp new file mode 100644 index 0000000..8a01808 --- /dev/null +++ b/src/electronics/components/demultiplexer.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "demultiplexer.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +#include + +Item* Demultiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Demultiplexer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Demultiplexer::libraryItem() +{ + return new LibraryItem( + "ec/demultiplexer", + i18n("Demultiplexer"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + Demultiplexer::construct + ); +} + +Demultiplexer::Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "demultiplexer" ) +{ + m_name = i18n("Demultiplexer"); + m_desc = i18n("Seperates the input data stream into components. The value of the input is passed to the \"X\" output selected by the binary number given by the \"A\" inputs."); + + m_input = 0l; + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(8); + property("addressSize")->setValue(1); + + // For backwards compatibility + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setMinValue(-1); + property("numInput")->setValue(-1); + property("numInput")->setHidden(true); +} + +Demultiplexer::~Demultiplexer() +{ +} + + +void Demultiplexer::dataChanged() +{ + if ( hasProperty("numInput") && dataInt("numInput") != -1 ) + { + int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) ); + property("numInput")->setValue(-1); + + if ( addressSize < 1 ) + addressSize = 1; + else if ( addressSize > 8 ) + addressSize = 8; + + // This function will get called again when we set the value of numInput + property("addressSize")->setValue(addressSize); + return; + } + + if ( hasProperty("numInput") ) + { + m_variantData["numInput"]->deleteLater(); + m_variantData.remove("numInput"); + } + + initPins( unsigned(dataInt("addressSize")) ); +} + + +void Demultiplexer::inStateChanged( bool /*state*/ ) +{ + unsigned long long pos = 0; + for ( unsigned i = 0; i < m_aLogic.size(); ++i ) + { + if ( m_aLogic[i]->isHigh() ) + pos += 1 << i; + } + for ( unsigned i = 0; i < m_xLogic.size(); ++i ) + m_xLogic[i]->setHigh( (pos == i) && m_input->isHigh() ); +} + + +void Demultiplexer::initPins( unsigned newAddressSize ) +{ + unsigned oldAddressSize = m_aLogic.size(); + unsigned long long oldXLogicCount = m_xLogic.size(); + unsigned long long newXLogicCount = 1 << newAddressSize; + + if ( newXLogicCount == oldXLogicCount ) + return; + + QStringList pins; + + for ( unsigned i=0; i=0; --i ) + pins += "X"+QString::number(i); + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + ECNode *node; + + if (!m_input) + { + node = ecNodeWithID("X"); + m_input = createLogicIn(node); + m_input->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) ); + } + + if ( newXLogicCount > oldXLogicCount ) + { + m_xLogic.resize(newXLogicCount); + for ( unsigned i = oldXLogicCount; i < newXLogicCount; ++i ) + { + node = ecNodeWithID("X"+QString::number(i)); + m_xLogic.insert( i, createLogicOut(node,false) ); + } + + m_aLogic.resize(newAddressSize); + for ( unsigned i = oldAddressSize; i < newAddressSize; ++i ) + { + node = ecNodeWithID("A"+QString::number(i)); + m_aLogic.insert( i, createLogicIn(node) ); + m_aLogic[i]->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) ); + } + } + else + { + for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i ) + { + QString id = "X"+QString::number(i); + removeDisplayText(id); + removeElement( m_xLogic[i], false ); + removeNode(id); + } + m_xLogic.resize(newXLogicCount); + + for ( unsigned i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = "A"+QString::number(i); + removeDisplayText(id); + removeElement( m_aLogic[i], false ); + removeNode(id); + } + m_aLogic.resize(newAddressSize); + } +} + diff --git a/src/electronics/components/demultiplexer.h b/src/electronics/components/demultiplexer.h new file mode 100644 index 0000000..a2b52dd --- /dev/null +++ b/src/electronics/components/demultiplexer.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2004-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. * + ***************************************************************************/ + +#ifndef DEMULTIPLEXER_H +#define DEMULTIPLEXER_H + +#include "component.h" +#include "logic.h" + +#include + +/** +@author David Saxton +*/ +class Demultiplexer : public CallbackClass, public Component +{ +public: + Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Demultiplexer(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void dataChanged(); + /** + * Add / remove pins according to the number of inputs the user has requested + */ + void initPins( unsigned addressSize ); + + void inStateChanged( bool newState ); + + QPtrVector m_aLogic; + QPtrVector m_xLogic; + LogicIn * m_input; +}; + +#endif diff --git a/src/electronics/components/dependentsource.cpp b/src/electronics/components/dependentsource.cpp new file mode 100644 index 0000000..764cc53 --- /dev/null +++ b/src/electronics/components/dependentsource.cpp @@ -0,0 +1,314 @@ +/*************************************************************************** + * 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 "dependentsource.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include "cccs.h" +#include "ccvs.h" +#include "vccs.h" +#include "vcvs.h" + +#include +#include + +//BEGIN class DependentSource +DependentSource::DependentSource( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + setSize( -16, -16, 32, 32 ); + + init2PinLeft(); + init2PinRight(); + + createProperty( "gain", Variant::Type::Double ); + property("gain")->setCaption( i18n("Gain") ); + property("gain")->setValue(1.0); + + addDisplayText( "gain", QRect( -16, -32, 32, 16 ), "" ); +} + + +DependentSource::~DependentSource() +{ +} + + +void DependentSource::drawOutline( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + // Top rectangle + p.drawRect( _x, _y+19, width(), 11 ); + + p.save(); + bool canSetCol = (p.pen().color() != Qt::color0) && (p.pen().color() != Qt::color1); + + // Bottom lines + if (canSetCol) + p.setPen( m_pNNode[1]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x, _y+40, _x+8, _y+40 ); // Left inny + + if (canSetCol) + p.setPen( m_pPNode[1]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x+width(), _y+40, _x+24, _y+40 ); // Right inny + + p.restore(); + + // Bottom diamond + QPointArray pa4(4); + pa4[0] = QPoint( _x+6, _y+40 ); + pa4[1] = QPoint( _x+16, _y+32 ); + pa4[2] = QPoint( _x+26, _y+40 ); + pa4[3] = QPoint( _x+16, _y+48 ); + p.drawPolygon(pa4); +} + + +void DependentSource::drawTopArrow( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + if ( p.pen().color() == m_selectedCol ) + p.setPen(Qt::black); + + if ( p.brush().color() == m_brushCol ) + p.setBrush(Qt::black); + + p.drawLine( _x+8, _y+24, _x+24, _y+24 ); + + QPointArray pa3(3); + pa3[0] = QPoint( _x+24, _y+24 ); + pa3[1] = QPoint( _x+19, _y+21 ); + pa3[2] = QPoint( _x+19, _y+27 ); + p.drawPolygon(pa3); +} + + +void DependentSource::drawBottomArrow( QPainter & p ) +{ + const int _x = (int)x()-16; + const int _y = (int)y()-32; + + if ( p.pen().color() == m_selectedCol ) + p.setPen(Qt::black); + + if ( p.brush().color() == m_brushCol ) + p.setBrush(Qt::black); + + p.drawLine( _x+11, _y+40, _x+21, _y+40 ); + + QPointArray pa3(3); + pa3[0] = QPoint( _x+21, _y+40 ); + pa3[1] = QPoint( _x+16, _y+37 ); + pa3[2] = QPoint( _x+16, _y+43 ); + p.drawPolygon(pa3); +} +//END class DependentSource + + +//BEGIN class ECCCCS +Item* ECCCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCCCS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCCCS::libraryItem() +{ + return new LibraryItem( + QString("ec/cccs"), + i18n("CCCS"), + i18n("Sources"), + "cccs.png", + LibraryItem::lit_component, + ECCCCS::construct ); +} + +ECCCCS::ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "cccs" ) +{ + m_name = i18n("Current Controlled Currrent Source"); + m_cccs = createCCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECCCCS::~ECCCCS() +{ +} + +void ECCCCS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_cccs->setGain(gain); +} + +void ECCCCS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawTopArrow(p); + drawBottomArrow(p); + deinitPainter(p); +} +//END class ECCCCS + + +//BEGIN class ECCCVS +Item* ECCCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCCVS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCCVS::libraryItem() +{ + return new LibraryItem( + QString("ec/ccvs"), + i18n("CCVS"), + i18n("Sources"), + "ccvs.png", + LibraryItem::lit_component, + ECCCVS::construct ); +} + +ECCCVS::ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "ccvs" ) +{ + m_name = i18n("Current Controlled Voltage Source"); + m_ccvs = createCCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECCCVS::~ECCCVS() +{ +} + +void ECCCVS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_ccvs->setGain(gain); +} + +void ECCCVS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawTopArrow(p); + deinitPainter(p); +} +//END class ECCCVS + + +//BEGIN class ECVCCS +Item* ECVCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVCCS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVCCS::libraryItem() +{ + return new LibraryItem( + QString("ec/vccs"), + i18n("VCCS"), + i18n("Sources"), + "vccs.png", + LibraryItem::lit_component, + ECVCCS::construct ); +} + +ECVCCS::ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "vccs" ) +{ + m_name = i18n("Voltage Controlled Current Source"); + m_vccs = createVCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECVCCS::~ECVCCS() +{ +} + +void ECVCCS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_vccs->setGain(gain); +} + +void ECVCCS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + drawBottomArrow(p); + deinitPainter(p); +} +//END class ECVCCS + + +//BEGIN class ECVCVS +Item* ECVCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVCVS( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVCVS::libraryItem() +{ + return new LibraryItem( + QString("ec/vcvs"), + i18n("VCVS"), + i18n("Sources"), + "vcvs.png", + LibraryItem::lit_component, + ECVCVS::construct ); +} + +ECVCVS::ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id ) + : DependentSource( icnDocument, newItem, id ? id : "vcvs" ) +{ + m_name = i18n("Voltage Controlled Voltage Source"); + m_vcvs = createVCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. ); + m_pNNode[1]->pin()->setGroundType( Pin::gt_medium ); +} + +ECVCVS::~ECVCVS() +{ +} + +void ECVCVS::dataChanged() +{ + double gain = dataDouble("gain"); + + QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' '); + setDisplayText( "gain", display ); + + m_vcvs->setGain(gain); +} + +void ECVCVS::drawShape( QPainter &p ) +{ + initPainter(p); + drawOutline(p); + deinitPainter(p); +} +//END class ECVCVS diff --git a/src/electronics/components/dependentsource.h b/src/electronics/components/dependentsource.h new file mode 100644 index 0000000..2bccbb7 --- /dev/null +++ b/src/electronics/components/dependentsource.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef DEPENDENTSOURCE_H +#define DEPENDENTSOURCE_H + +#include "component.h" + +/** +@author David Saxton +*/ +class DependentSource : public Component +{ + public: + DependentSource( ICNDocument *icnDocument, bool newItem, const char *id ); + ~DependentSource(); + virtual bool canFlip() const { return true; } + + protected: + void drawOutline( QPainter & p ); + void drawTopArrow( QPainter & p ); + void drawBottomArrow( QPainter & p ); +}; + +/** +@short Current Controlled Current Source +@author David Saxton +*/ +class ECCCCS : public DependentSource +{ + public: + ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCCCS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + CCCS *m_cccs; +}; + +/** +@short Current Controlled Voltage Source +@author David Saxton +*/ +class ECCCVS : public DependentSource +{ + public: + ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCCVS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + CCVS *m_ccvs; +}; + +/** +@short Voltage Controlled Current Source +@author David Saxton +*/ +class ECVCCS : public DependentSource +{ + public: + ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVCCS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + VCCS *m_vccs; +}; + +/** +@short Voltage Controlled Voltage Source +@author David Saxton +*/ +class ECVCVS : public DependentSource +{ + public: + ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVCVS(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + VCVS *m_vcvs; +}; + +#endif diff --git a/src/electronics/components/discretelogic.cpp b/src/electronics/components/discretelogic.cpp new file mode 100644 index 0000000..e2e284e --- /dev/null +++ b/src/electronics/components/discretelogic.cpp @@ -0,0 +1,308 @@ +/*************************************************************************** + * 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 "canvasitemparts.h" +#include "discretelogic.h" +#include "ecnode.h" +#include "logic.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include + + +//BEGIN class Inverter +Item* Inverter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Inverter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Inverter::libraryItem() +{ + QStringList ids; + ids << "ec/inverter" << "ec/not"; + return new LibraryItem( + ids, + i18n("Inverter"), + i18n("Logic"), + "not.png", + LibraryItem::lit_component, + Inverter::construct ); +} + +Inverter::Inverter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "not" ) +{ + m_name = i18n("Inverter"); + m_desc = i18n("The output is the logical inverse of the logic-input state."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pIn = createLogicIn(m_pNNode[0]); + m_pOut = createLogicOut( m_pPNode[0], true ); + + m_pIn->setCallback( this, (CallbackPtr)(&Inverter::inStateChanged) ); + inStateChanged(false); +} + + +Inverter::~Inverter() +{ +} + + +void Inverter::inStateChanged( bool newState ) +{ + (static_cast(m_pOut))->setHigh( !newState ); +} + + +void Inverter::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPointArray pa(3); + pa[0] = QPoint( _x, _y ); + pa[1] = QPoint( _x+width()-6, _y+(height()/2) ); + pa[2] = QPoint( _x, _y+height() ); + p.drawPolygon(pa); + p.drawPolyline(pa); + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 7, 7 ); + deinitPainter(p); +} +//END class Inverter + + +//BEGIN class Buffer +Item* Buffer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Buffer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Buffer::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/buffer"), + i18n("Buffer"), + i18n("Logic"), + "buffer.png", + LibraryItem::lit_component, + Buffer::construct ); +} + +Buffer::Buffer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "buffer" ) +{ + m_name = i18n("Buffer"); + m_desc = i18n("Cleans the logic input, with the output high or low depending on input trigger levels."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pIn = createLogicIn(m_pNNode[0]); + m_pOut = createLogicOut( m_pPNode[0], true ); + + m_pIn->setCallback( this, (CallbackPtr)(&Buffer::inStateChanged) ); + inStateChanged(false); +} + + +Buffer::~Buffer() +{ +} + + +void Buffer::inStateChanged( bool newState ) +{ + m_pOut->setHigh(newState); +} + + +void Buffer::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPointArray pa(3); + pa[0] = QPoint( _x, _y ); + pa[1] = QPoint( _x+width(), _y+(height()/2) ); + pa[2] = QPoint( _x, _y+height() ); + p.drawPolygon(pa); + p.drawPolyline(pa); + deinitPainter(p); +} +//END class Buffer + + +//BEGIN class ECLogicInput +Item* ECLogicInput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLogicInput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLogicInput::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/logic_input"), + i18n("Logic Input"), + i18n("Logic"), + "logic_input.png", + LibraryItem::lit_component, + ECLogicInput::construct ); +} + +ECLogicInput::ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "logic_input" ) +{ + m_name = i18n("Logic Input"); + m_desc = i18n("Provides a user-adjustable logic state.

" + "Click to pulse high, or drag the mouse off to keep the output high."); + setSize( -8, -8, 16, 16 ); + + b_state = false; + addButton( "button", QRect( -24, -8, 16, 16 ), "", true ); + + createProperty( "useToggle", Variant::Type::Bool ); + property("useToggle")->setCaption( i18n("Use Toggle") ); + property("useToggle")->setValue(true); + + init1PinRight(); + + m_pOut = createLogicOut( m_pPNode[0], false ); +} + + +ECLogicInput::~ECLogicInput() +{ +} + + +void ECLogicInput::dataChanged() +{ + button("button")->setToggle( dataBool("useToggle") ); +} + + +void ECLogicInput::drawShape( QPainter &p ) +{ + initPainter(p); + if (b_state) + p.setBrush( QColor( 255, 166, 0 ) ); + else + p.setBrush( Qt::white ); + p.drawEllipse( (int)x()-4, (int)y()-6, 12, 12 ); + deinitPainter(p); +} + + +void ECLogicInput::buttonStateChanged( const QString &, bool state ) +{ + b_state = state; + m_pOut->setHigh(b_state); +} +//END class ECLogicInput + + +//BEGIN class ECLogicOutput +Item* ECLogicOutput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLogicOutput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLogicOutput::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/logic_output"), + i18n("Logic Output"), + i18n("Logic"), + "logic_output.png", + LibraryItem::lit_component, + ECLogicOutput::construct ); +} + +ECLogicOutput::ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "logic_output" ) +{ + m_name = i18n("Logic Output"); + m_desc = i18n("Shows the logic-state of the input."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + m_pIn = createLogicIn(m_pNNode[0]); + + m_pSimulator = Simulator::self(); + + m_lastDrawState = 0.0; + m_lastSwitchTime = m_lastDrawTime = m_pSimulator->time(); + m_highTime = 0; + m_bLastState = false; + m_bDynamicContent = true; + + m_pIn->setCallback( this, (CallbackPtr)(&ECLogicOutput::inStateChanged) ); +} + +ECLogicOutput::~ECLogicOutput() +{ +} + +void ECLogicOutput::inStateChanged( bool newState ) +{ + if ( m_bLastState == newState ) + return; + + unsigned long long newTime = m_pSimulator->time(); + unsigned long long dt = newTime - m_lastSwitchTime; + + m_lastSwitchTime = newTime; + + m_bLastState = newState; + if (!newState) + { + // Gone from high to low + m_highTime += dt; + } +} + + +void ECLogicOutput::drawShape( QPainter &p ) +{ + unsigned long long newTime = m_pSimulator->time(); + unsigned long long runTime = newTime - m_lastDrawTime; + m_lastDrawTime = newTime; + + if (m_bLastState) + { + // Logic in is currently high + m_highTime += newTime - m_lastSwitchTime; + } + + double state; + + if ( runTime == 0 ) + state = m_lastDrawState; + + else + state = m_lastDrawState = double(m_highTime)/double(runTime); + + initPainter(p); + p.setBrush( QColor( 255, uint(255-state*(255-166)), uint((1-state)*255) ) ); + p.drawEllipse( int(x()-8), int(y()-8), width(), height() ); + deinitPainter(p); + + m_lastSwitchTime = newTime; + m_highTime = 0; +} +//END class ECLogicOutput + diff --git a/src/electronics/components/discretelogic.h b/src/electronics/components/discretelogic.h new file mode 100644 index 0000000..82775bf --- /dev/null +++ b/src/electronics/components/discretelogic.h @@ -0,0 +1,110 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef DISCRETELOGIC_H +#define DISCRETELOGIC_H + +#include "component.h" +#include "logic.h" + +class Simulator; + +/** +@short Boolean NOT +@author David Saxton +*/ +class Inverter : public CallbackClass, public Component +{ + public: + Inverter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Inverter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + LogicIn * m_pIn; + LogicOut * m_pOut; +}; + +/** +@short Buffer +@author David Saxton +*/ +class Buffer : public CallbackClass, public Component +{ +public: + Buffer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Buffer(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + LogicIn * m_pIn; + LogicOut * m_pOut; +}; + +/** +@short Boolean logic input +@author David Saxton +*/ +class ECLogicInput : public Component +{ +public: + ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLogicInput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + +private: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + LogicOut * m_pOut; + bool b_state; +}; + +/** +@short Boolean logic output +@author David Saxton +*/ +class ECLogicOutput : public CallbackClass, public Component +{ + public: + ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLogicOutput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); + + unsigned long long m_lastDrawTime; + unsigned long long m_lastSwitchTime; + unsigned long long m_highTime; + bool m_bLastState; + + double m_lastDrawState; + LogicIn * m_pIn; + Simulator * m_pSimulator; +}; + +#endif diff --git a/src/electronics/components/ec555.cpp b/src/electronics/components/ec555.cpp new file mode 100644 index 0000000..eccf2bd --- /dev/null +++ b/src/electronics/components/ec555.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "ec555.h" + +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include +#include +#include + +Item* EC555::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new EC555( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* EC555::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/555"), + i18n("555"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + EC555::construct + ); +} + +EC555::EC555( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "555" ) +{ + m_name = i18n("555"); + m_desc = i18n("Common timer IC"); +// m_pins = QStringList::split( ',', "Gnd,Trg,Out,Res,CV,Th,Dis,Vcc" ); +// m_pins = QStringList::split( ',', "Dis,Th,Trg,Gnd,CV,Out,Res,Vcc" ); + + old_com1 = false; + old_com2 = false; + old_q = false; + + setSize( -32, -32, 64, 64 ); + + + // Pins down left + + // Pin 7 + discharge = createPin( -40, -16, 0, "Dis" )->pin(); + addDisplayText( "dis", QRect( -32, -24, 24, 16 ), "Dis" ); + + // Pin 6 + threshold = createPin( -40, 0, 0, "Th" )->pin(); + addDisplayText( "th", QRect( -32, -8, 24, 16 ), "Th" ); + + // Pin 2 + trigger = createPin( -40, 16, 0, "Trg" )->pin(); + addDisplayText( "trg", QRect( -32, 8, 24, 16 ), "Trg" ); + + + + // Top two + + // Pin 8 + vcc = createPin( -16, -40, 90, "Vcc" )->pin(); + addDisplayText( "vcc", QRect( -24, -32, 16, 8 ), "+" ); + + // Pin 4 + reset = createPin( 16, -40, 90, "Res" )->pin(); + addDisplayText( "res", QRect( 8, -28, 16, 16 ), "Res" ); + + + + // Bottom two + + // Pin 1 + ground = createPin( -16, 40, 270, "Gnd" )->pin(); + addDisplayText( "gnd", QRect( -24, 20, 16, 8 ), "-" ); + + // Pin 5 + control = createPin( 16, 40, 270, "CV" )->pin(); + addDisplayText( "cv", QRect( 8, 12, 16, 16 ), "CV" ); + + + + // Output on right + + // Pin 3 + output = createPin( 40, 0, 180, "Out" )->pin(); + addDisplayText( "out", QRect( 8, -8, 16, 16 ), "Out" ); + + + + m_r1 = createResistance( vcc, control, 5e3 ); + m_r23 = createResistance( control, ground, 1e4 ); + m_po_sink = createResistance( output, ground, 0. ); + m_po_source = createResistance( output, vcc, 0. ); + m_po_source->setConductance(0.); + m_r_discharge = createResistance( discharge, ground, 0. ); +} + + +EC555::~EC555() +{ +} + +void EC555::stepNonLogic() +{ + double v_threshold = threshold->voltage(); + double v_control = control->voltage(); + double v_ground = ground->voltage(); + double v_trigger = trigger->voltage(); + double v_reset = reset->voltage(); + double v_vcc = vcc->voltage(); + + double v_r = (v_control+v_ground)/2; + + bool com1 = ( v_threshold == v_control ) ? old_com1 : ( v_threshold < v_control ); + bool com2 = ( v_r == v_trigger ) ? old_com2 : ( v_r > v_trigger ); + bool reset = ( v_reset >= (v_control-v_ground)/2 + v_ground ); + old_com1 = com1; + old_com2 = com2; + + bool r = ( !reset || !com1 ); + bool s = com2; + + bool q = old_q; + if ( v_vcc - v_ground >= 2.5 ) + { + if ( s && !r ) + { + q = true; + } + else if ( r && !s ) + { + q = false; + } + } + else + { + q = false; + } + old_q = q; + + + m_r_discharge->setConductance(0.); + + if (q) + { + m_po_source->setResistance(10.); + m_po_sink->setConductance(0.); + } + else + { + m_po_source->setConductance(0.); + m_po_sink->setResistance(10.); + if ( v_ground+0.7 <= v_vcc ) + { + m_r_discharge->setResistance(10.); + } + } +} + + diff --git a/src/electronics/components/ec555.h b/src/electronics/components/ec555.h new file mode 100644 index 0000000..edeb2a5 --- /dev/null +++ b/src/electronics/components/ec555.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef EC555_H +#define EC555_H + +#include "component.h" + +#include + +/** +@short 555 IC +@author David Saxton +*/ +class EC555 : public Component +{ +public: + EC555( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~EC555(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + Pin * ground; + Pin * trigger; + Pin * output; + Pin * reset; + Pin * control; + Pin * threshold; + Pin * discharge; + Pin * vcc; + + Resistance *m_r1; + Resistance *m_r23; + Resistance *m_po_sink; + Resistance *m_po_source; + Resistance *m_r_discharge; + + bool old_com1; + bool old_com2; + bool old_q; +}; + +#endif diff --git a/src/electronics/components/ecbcdto7segment.cpp b/src/electronics/components/ecbcdto7segment.cpp new file mode 100644 index 0000000..fb210ea --- /dev/null +++ b/src/electronics/components/ecbcdto7segment.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecbcdto7segment.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +// Values for a,b,c,d,e,f,g of common-anode 7 segment display +bool numbers[16][7] = + { { 1, 1, 1, 1, 1, 1, 0 }, // 0 + { 0, 1, 1, 0, 0, 0, 0 }, // 1 + { 1, 1, 0, 1, 1, 0, 1 }, // 2 + { 1, 1, 1, 1, 0, 0, 1 }, // 3 + { 0, 1, 1, 0 ,0, 1, 1 }, // 4 + { 1, 0, 1, 1, 0, 1, 1 }, // 5 + { 1, 0, 1, 1, 1, 1, 1 }, // 6 + { 1, 1, 1, 0, 0, 0, 0 }, // 7 + { 1, 1, 1, 1, 1, 1, 1 }, // 8 + { 1, 1, 1, 0, 0, 1, 1 }, // 9 + { 1, 1, 1, 0, 1, 1, 1 }, // A + { 0, 0, 1, 1, 1, 1, 1 }, // b + { 1, 0, 0, 1, 1, 1, 0 }, // C + { 0, 1, 1, 1, 1, 0, 1 }, // d + { 1, 0, 0, 1, 1, 1, 1 }, // E + { 1, 0, 0, 0, 1, 1, 1 } }; // F + +Item* ECBCDTo7Segment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECBCDTo7Segment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECBCDTo7Segment::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/bcd_to_seven_segment"), + i18n("BCD to 7 Segment"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + ECBCDTo7Segment::construct + ); +} + +ECBCDTo7Segment::ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "bcd_to_seven_segment" ) +{ + m_name = i18n("BCD to Seven Segment"); + m_desc = i18n("Converts a binary-coded-input to a form displayable by a seven segment display.

" + "Normal operation: lt (Lamp Test) and the rb (Ripple Blanking) are held high, en (Enable) is held low."); + + ALogic = BLogic = CLogic = DLogic = 0L; + ltLogic = rbLogic = enLogic = 0L; + + for ( int i=0; i<7; i++ ) + { + outLogic[i] = 0L; + oldOut[i] = false; + } + + QStringList pins = QStringList::split( ',', "A,B,C,D,,lt,rb,en,d,e,f,g,,a,b,c", true ); + initDIPSymbol( pins, 48 ); + initDIP(pins); + + ALogic = createLogicIn( ecNodeWithID("A") ); + BLogic = createLogicIn( ecNodeWithID("B") ); + CLogic = createLogicIn( ecNodeWithID("C") ); + DLogic = createLogicIn( ecNodeWithID("D") ); + ltLogic = createLogicIn( ecNodeWithID("lt") ); + rbLogic = createLogicIn( ecNodeWithID("rb") ); + enLogic = createLogicIn( ecNodeWithID("en") ); + + ALogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + BLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + CLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + DLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + ltLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + rbLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + enLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + + for ( uint i=0; i<7; ++i ) + { + outLogic[i] = createLogicOut( ecNodeWithID( QChar('a'+i) ), false ); + outLogic[i]->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) ); + } + inStateChanged(false); +} + +ECBCDTo7Segment::~ECBCDTo7Segment() +{ +} + +void ECBCDTo7Segment::inStateChanged(bool) +{ + bool A = ALogic->isHigh(); + bool B = BLogic->isHigh(); + bool C = CLogic->isHigh(); + bool D = DLogic->isHigh(); + bool lt = ltLogic->isHigh(); // Lamp test + bool rb = rbLogic->isHigh(); // Ripple Blank + bool en = enLogic->isHigh(); // Enable (store) + + int n = A + 2*B + 4*C + 8*D; +// if ( n > 9 ) n = 0; + + bool out[7]; + + if (lt) // Lamp test + { + if (rb) // Ripple blanking + { + if (en) // Enable (store) + { + for ( int i=0; i<7; i++ ) + { + out[i] = oldOut[i]; + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = numbers[n][i]; + oldOut[i] = out[i]; + } + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = false; + } + } + } + else + { + for ( int i=0; i<7; i++ ) + { + out[i] = true; + } + } + + for ( int i=0; i<7; i++ ) + { + outLogic[i]->setHigh( out[i] ); + } +} diff --git a/src/electronics/components/ecbcdto7segment.h b/src/electronics/components/ecbcdto7segment.h new file mode 100644 index 0000000..03d4c2b --- /dev/null +++ b/src/electronics/components/ecbcdto7segment.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECBCDTO7SEGMENT_H +#define ECBCDTO7SEGMENT_H + +#include "component.h" +#include "logic.h" + +/** +@short Converts a BCD input to 7-Segment Output +@author David Saxton +*/ +class ECBCDTo7Segment : public CallbackClass, public Component +{ +public: + ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECBCDTo7Segment(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + LogicIn *ALogic, *BLogic, *CLogic, *DLogic; + LogicIn *ltLogic, *rbLogic, *enLogic; + LogicOut *outLogic[7]; + + // Old values + bool oldOut[7]; +}; + +#endif diff --git a/src/electronics/components/ecbjt.cpp b/src/electronics/components/ecbjt.cpp new file mode 100644 index 0000000..b4b59f2 --- /dev/null +++ b/src/electronics/components/ecbjt.cpp @@ -0,0 +1,153 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "bjt.h" +#include "ecbjt.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include +#include + +Item * ECBJT::constructNPN( ItemDocument * itemDocument, bool newItem, const char * id ) +{ + return new ECBJT( true, (ICNDocument*)itemDocument, newItem, id ); +} + + +Item * ECBJT::constructPNP( ItemDocument * itemDocument, bool newItem, const char * id ) +{ + return new ECBJT( false, (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ECBJT::libraryItemNPN() +{ + return new LibraryItem( + "ec/npnbjt", + i18n("NPN"), + i18n("Discrete"), + "npn.png", + LibraryItem::lit_component, + ECBJT::constructNPN ); +} + + +LibraryItem* ECBJT::libraryItemPNP() +{ + return new LibraryItem( + "ec/pnpbjt", + i18n("PNP"), + i18n("Discrete"), + "pnp.png", + LibraryItem::lit_component, + ECBJT::constructPNP ); +} + + +ECBJT::ECBJT( bool isNPN, ICNDocument * icnDocument, bool newItem, const char * id ) + : Component( icnDocument, newItem, id ? id : (isNPN ? "npnbjt" : "pnpbjt") ) +{ + m_bIsNPN = isNPN; + if ( m_bIsNPN ) + m_name = i18n("NPN Transistor"); + else + m_name = i18n("PNP Transistor"); + + setSize( -8, -8, 16, 16 ); + m_pBJT = createBJT( createPin( 8, -16, 90, "c" ), createPin( -16, 0, 0, "b" ), createPin( 8, 16, 270, "e" ), m_bIsNPN ); + + BJTSettings s; // will be created with the default settings + + Variant * v = createProperty( "I_S", Variant::Type::Double ); + v->setCaption("Saturation Current"); + v->setUnit("A"); + v->setMinValue(1e-20); + v->setMaxValue(1e-0); + v->setValue( s.I_S ); + v->setAdvanced(true); + + v = createProperty( "N_F", Variant::Type::Double ); + v->setCaption( i18n("Forward Coefficient") ); + v->setMinValue(1e0); + v->setMaxValue(1e1); + v->setValue( s.N_F ); + v->setAdvanced(true); + + v = createProperty( "N_R", Variant::Type::Double ); + v->setCaption( i18n("Reverse Coefficient") ); + v->setMinValue(1e0); + v->setMaxValue(1e1); + v->setValue( s.N_R ); + v->setAdvanced(true); + + v = createProperty( "B_F", Variant::Type::Double ); + v->setCaption( i18n("Forward Beta") ); + v->setMinValue(1e-1); + v->setMaxValue(1e3); + v->setValue( s.B_F ); + v->setAdvanced(true); + + v = createProperty( "B_R", Variant::Type::Double ); + v->setCaption( i18n("Reverse Beta") ); + v->setMinValue(1e-1); + v->setMaxValue(1e3); + v->setValue( s.B_R ); + v->setAdvanced(true); +} + +ECBJT::~ECBJT() +{ +} + + +void ECBJT::dataChanged() +{ + BJTSettings s; + s.I_S = dataDouble( "I_S" ); + s.N_F = dataDouble( "N_F" ); + s.N_R = dataDouble( "N_R" ); + s.B_F = dataDouble( "B_F" ); + s.B_R = dataDouble( "B_R" ); + + m_pBJT->setBJTSettings( s ); +} + + +void ECBJT::drawShape( QPainter &p ) +{ + const int _x = int(x()); + const int _y = int(y()); + + initPainter(p); + + p.drawLine( _x-8, _y-8, _x-8, _y+8 ); + p.drawLine( _x+8, _y-8, _x-8, _y ); + p.drawLine( _x+8, _y+8, _x-8, _y ); + + QPointArray pa(3); + if ( m_bIsNPN ) + { + pa[0] = QPoint( _x+6, _y+7 ); + pa[1] = QPoint( _x+2, _y+8 ); + pa[2] = QPoint( _x+6, _y+3 ); + } + else + { + pa[0] = QPoint( _x-7, _y+1 ); + pa[1] = QPoint( _x-4, _y+5 ); + pa[2] = QPoint( _x-2, _y ); + } + p.setBrush( p.pen().color() ); + p.drawPolygon(pa); + + deinitPainter(p); +} diff --git a/src/electronics/components/ecbjt.h b/src/electronics/components/ecbjt.h new file mode 100644 index 0000000..17a63e9 --- /dev/null +++ b/src/electronics/components/ecbjt.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef ECBJT_H +#define ECBJT_H + +#include "component.h" + +class BJT; + +/** +@short Simulates a BJT +@author David Saxton +*/ +class ECBJT : public Component +{ + public: + ECBJT( bool isNPN, ICNDocument *icnDocument, bool newItem, const char * id = 0L ); + ~ECBJT(); + virtual bool canFlip() const { return true; } + + static Item * constructNPN( ItemDocument * itemDocument, bool newItem, const char * id ); + static Item * constructPNP( ItemDocument * itemDocument, bool newItem, const char * id ); + static LibraryItem * libraryItemNPN(); + static LibraryItem * libraryItemPNP(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + bool m_bIsNPN; + BJT * m_pBJT; +}; + +#endif diff --git a/src/electronics/components/eccapacitor.cpp b/src/electronics/components/eccapacitor.cpp new file mode 100644 index 0000000..76a09b0 --- /dev/null +++ b/src/electronics/components/eccapacitor.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "capacitance.h" +#include "eccapacitor.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include + +Item* ECCapacitor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCapacitor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCapacitor::libraryItem() +{ + return new LibraryItem( + "ec/capacitor", + i18n("Capacitor"), + i18n("Discrete"), + "capacitor.png", + LibraryItem::lit_component, + ECCapacitor::construct + ); +} + +ECCapacitor::ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "capacitor" ) +{ + m_name = i18n("Capacitor"); + m_desc = i18n("Stores electrical charge.

" + "The voltage across the capacitor and capacitance are related by Charge = Capacitance x Voltage."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_capacitance = createCapacitance( m_pNNode[0], m_pPNode[0], 0.001 ); + + createProperty( "Capacitance", Variant::Type::Double ); + property("Capacitance")->setCaption( i18n("Capacitance") ); + property("Capacitance")->setUnit("F"); + property("Capacitance")->setMinValue(1e-12); + property("Capacitance")->setMaxValue(1e12); + property("Capacitance")->setValue(1e-3); + + addDisplayText( "capacitance", QRect( -8, -24, 16, 16 ), "", false ); +} + +ECCapacitor::~ECCapacitor() +{ +} + +void ECCapacitor::dataChanged() +{ + double capacitance = dataDouble("Capacitance"); + + QString display = QString::number( capacitance / getMultiplier(capacitance), 'g', 3 ) + getNumberMag(capacitance) + "F"; + setDisplayText( "capacitance", display ); + + m_capacitance->setCapacitance(capacitance); +} + +void ECCapacitor::drawShape( QPainter &p ) +{ + initPainter(p); + + int _y = (int)y()-8; + int _x = (int)x()-8; + + QPen pen; + pen.setWidth(1); + pen.setColor( p.pen().color() ); + p.setPen(pen); + p.drawRect( _x, _y, 5, 16 ); + p.drawRect( _x+11, _y, 5, 16 ); + + + deinitPainter(p); +// p.drawPolyline( areaPoints() ); +} + + diff --git a/src/electronics/components/eccapacitor.h b/src/electronics/components/eccapacitor.h new file mode 100644 index 0000000..4dd0ee6 --- /dev/null +++ b/src/electronics/components/eccapacitor.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECCAPACITOR_H +#define ECCAPACITOR_H + +#include "component.h" + +class Capacitance; +class ECNode; + +/** +@short Capacitor +Simple capacitor +@author David Saxton +*/ +class ECCapacitor : public Component +{ +public: + ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCapacitor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + + Capacitance * m_capacitance; +}; + +#endif diff --git a/src/electronics/components/ecclockinput.cpp b/src/electronics/components/ecclockinput.cpp new file mode 100644 index 0000000..7f1ec9c --- /dev/null +++ b/src/electronics/components/ecclockinput.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "ecclockinput.h" + +#include "logic.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include + +#include + +static inline uint roundDouble( const double x ) +{ + return uint(std::floor(x+0.5)); +} + +Item* ECClockInput::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECClockInput( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECClockInput::libraryItem() +{ + return new LibraryItem( + QString("ec/clock_input"), + i18n("Clock Input"), + i18n("Logic"), + "clockinput.png", + LibraryItem::lit_component, + ECClockInput::construct ); +} + +ECClockInput::ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "clock_input" ) +{ + m_name = i18n("Clock Input"); + m_desc = i18n("A square-wave generator, outputing logical high/low at repeating time intervals."); + setSize( -16, -8, 32, 16 ); + + m_lastSetTime = 0; + m_time = 0; + m_high_time = 0; + m_low_time = 0; + m_period = 0; + m_bSetStepCallbacks = true; + m_pSimulator = Simulator::self(); + + for ( unsigned i = 0; i < 1000; i++ ) + { + ComponentCallback * ccb = new ComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepCallback) ); + m_pComponentCallback[i] = new LinkedList(ccb); + } + + init1PinRight(); + m_pOut = createLogicOut( m_pPNode[0], false ); + + createProperty( "low-time", Variant::Type::Double ); + property("low-time")->setUnit("S"); + property("low-time")->setCaption( i18n("Low Time") ); + property("low-time")->setMinValue(1.0/LOGIC_UPDATE_RATE); + property("low-time")->setValue(0.5); + + createProperty( "high-time", Variant::Type::Double ); + property("high-time")->setUnit("S"); + property("high-time")->setCaption( i18n("High Time") ); + property("high-time")->setMinValue(1.0/LOGIC_UPDATE_RATE); + property("high-time")->setValue(0.5); + + addDisplayText( "freq", QRect( -16, -24, 32, 14 ), "", false ); +} + + +ECClockInput::~ECClockInput() +{ + for ( unsigned i = 0; i < 1000; i++ ) + { + delete m_pComponentCallback[i]->data(); + delete m_pComponentCallback[i]; + } +} + + +void ECClockInput::dataChanged() +{ + m_high_time = roundDouble(dataDouble("high-time")*LOGIC_UPDATE_RATE); + m_low_time = roundDouble(dataDouble("low-time")*LOGIC_UPDATE_RATE); + m_period = m_low_time+m_high_time; + + const double frequency = 1./(dataDouble("high-time")+dataDouble("low-time")); + QString display = QString::number( frequency / getMultiplier(frequency), 'g', 3 ) + getNumberMag(frequency) + "Hz"; + setDisplayText( "freq", display ); + + bool setStepCallbacks = m_period > 100; + if ( setStepCallbacks != m_bSetStepCallbacks ) + { + m_bSetStepCallbacks = setStepCallbacks; + if (setStepCallbacks) + m_pSimulator->detachComponentCallbacks(this); + else + m_pSimulator->attachComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepLogic) ); + } + + m_bLastStepCallbackOut = false; + m_lastSetTime = m_pSimulator->time(); +} + + +void ECClockInput::stepLogic() +{ + m_pOut->setHigh( m_time>m_low_time ); + + if ( ++m_time > m_period ) { + m_time -= int(m_time/m_period)*m_period; + } +} + + +void ECClockInput::stepCallback() +{ + m_pOut->setHigh(m_bLastStepCallbackOut); + m_bLastStepCallbackOut = !m_bLastStepCallbackOut; +} + + +void ECClockInput::stepNonLogic() +{ + if (!m_bSetStepCallbacks) + return; + + bool addingHigh = !m_bLastStepCallbackOut; + + //TODO 100 number shouldn't be hard-coded + long long lowerTime = m_pSimulator->time(); + long long upperTime = lowerTime + 100; + + long long upTo = m_lastSetTime; + + while ( upTo + (addingHigh?m_high_time:m_low_time) < upperTime ) + { + upTo += addingHigh ? m_high_time : m_low_time; + addingHigh = !addingHigh; + + long long at = upTo-lowerTime; + if ( at >= 0 && at < 100 ) + m_pSimulator->addStepCallback( at, m_pComponentCallback[at] ); + } + + m_lastSetTime = upTo; +} + + +void ECClockInput::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-10; + int _y = (int)y()-8; + + p.drawRect( _x-6, _y, 32, 16 ); + + p.drawLine( _x, _y+8, _x, _y+4 ); + p.drawLine( _x, _y+4, _x+4, _y+4 ); + p.drawLine( _x+4, _y+4, _x+4, _y+12 ); + p.drawLine( _x+4, _y+12, _x+8, _y+12 ); + p.drawLine( _x+8, _y+12, _x+8, _y+4 ); + p.drawLine( _x+8, _y+4, _x+12, _y+4 ); + p.drawLine( _x+12, _y+4, _x+12, _y+12 ); + p.drawLine( _x+12, _y+12, _x+16, _y+12 ); + p.drawLine( _x+16, _y+12, _x+16, _y+4 ); + p.drawLine( _x+16, _y+4, _x+20, _y+4 ); + p.drawLine( _x+20, _y+4, _x+20, _y+8 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/ecclockinput.h b/src/electronics/components/ecclockinput.h new file mode 100644 index 0000000..c7f7d14 --- /dev/null +++ b/src/electronics/components/ecclockinput.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef ECCLOCKINPUT_H +#define ECCLOCKINPUT_H + +#include "component.h" + +class ComponentCallback; +class Simulator; + +template +class LinkedList; + +/** +@short Boolean clock input +@author David Saxton +*/ +class ECClockInput : public Component +{ +public: + ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECClockInput(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + void stepCallback(); + void stepLogic(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + uint m_time; + uint m_high_time; + uint m_low_time; + uint m_period; + long long m_lastSetTime; + LogicOut * m_pOut; + bool m_bSetStepCallbacks; + bool m_bLastStepCallbackOut; + Simulator * m_pSimulator; + LinkedList * m_pComponentCallback[1000]; +}; + +#endif diff --git a/src/electronics/components/eccurrentsignal.cpp b/src/electronics/components/eccurrentsignal.cpp new file mode 100644 index 0000000..e6dc351 --- /dev/null +++ b/src/electronics/components/eccurrentsignal.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "currentsignal.h" +#include "eccurrentsignal.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" +#include "simulator.h" + +#include +#include + +Item* ECCurrentSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCurrentSignal( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCurrentSignal::libraryItem() +{ + return new LibraryItem( + QString("ec/ac_current"), + i18n("Current Signal"), + i18n("Sources"), + "currentsignal.png", + LibraryItem::lit_component, + ECCurrentSignal::construct ); +} + +ECCurrentSignal::ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "current_signal" ) +{ + m_name = i18n("Current Signal"); + m_desc = i18n("Provides a variety of current signals"); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_low ); + m_currentSignal = createCurrentSignal( m_pNNode[0], m_pPNode[0], 0. ); + m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. ); + + createProperty( "1-frequency", Variant::Type::Double ); + property("1-frequency")->setCaption( i18n("Frequency") ); + property("1-frequency")->setUnit("Hz"); + property("1-frequency")->setMinValue(1e-9); + property("1-frequency")->setMaxValue(1e3); + property("1-frequency")->setValue(50.0); + + createProperty( "1-current", Variant::Type::Double ); + property("1-current")->setCaption( i18n("Current Range") ); + property("1-current")->setUnit("A"); + property("1-current")->setMinValue(-1e12); + property("1-current")->setMaxValue(1e12); + property("1-current")->setValue(0.02); + + addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" ); + addDisplayText( "current", QRect( -16, -24, 32, 16 ), "" ); +} + + +ECCurrentSignal::~ECCurrentSignal() +{ +} + +void ECCurrentSignal::dataChanged() +{ + const double current = dataDouble("1-current"); + const double frequency = dataDouble("1-frequency"); + + QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A"; + setDisplayText( "current", display ); + + m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency ); + m_currentSignal->setCurrent(current); +} + +void ECCurrentSignal::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() ); + deinitPainter(p); +} + diff --git a/src/electronics/components/eccurrentsignal.h b/src/electronics/components/eccurrentsignal.h new file mode 100644 index 0000000..88dd276 --- /dev/null +++ b/src/electronics/components/eccurrentsignal.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECCURRENTSIGNAL_H +#define ECCURRENTSIGNAL_H + +#include "component.h" + +/** +@short Provides a current signal (sinusoidal, square, etc) +@author David Saxton +*/ +class ECCurrentSignal : public Component +{ +public: + ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCurrentSignal(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + CurrentSignal *m_currentSignal; +}; + +#endif diff --git a/src/electronics/components/eccurrentsource.cpp b/src/electronics/components/eccurrentsource.cpp new file mode 100644 index 0000000..76ecf3e --- /dev/null +++ b/src/electronics/components/eccurrentsource.cpp @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "currentsource.h" +#include "eccurrentsource.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +Item* ECCurrentSource::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCurrentSource( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCurrentSource::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/current_source"), + i18n("Current Source"), + i18n("Sources"), + "current_source.png", + LibraryItem::lit_component, + ECCurrentSource::construct ); +} + +ECCurrentSource::ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "current_source" ) +{ + m_name = i18n("Current Source"); + m_desc = i18n("Provides a fixed current source."); + setSize( -16, -8, 24, 24 ); + + init1PinLeft(8); + init1PinRight(8); + m_pNNode[0]->pin()->setGroundType( Pin::gt_low ); + + m_currentSource = createCurrentSource( m_pNNode[0], m_pPNode[0], 0. ); + + createProperty( "current", Variant::Type::Double ); + property("current")->setCaption( i18n("Current") ); + property("current")->setUnit("A"); + property("current")->setMinValue(-1e12); + property("current")->setMaxValue(1e12); + property("current")->setValue(0.02); + + addDisplayText("current", QRect( -16, -16, 24, 0 ), "" ); +} + + +ECCurrentSource::~ECCurrentSource() +{ +} + +void ECCurrentSource::dataChanged() +{ + double current = dataDouble("current"); + m_currentSource->setCurrent(current); + + QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A"; + setDisplayText("current", display ); +} + +void ECCurrentSource::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-24; + + // Top arrow indicating current direction + p.drawLine( _x+width(), _y+19, _x, _y+19 ); + p.drawLine( _x+width(), _y+19, _x+width()-3, _y+16 ); + p.drawLine( _x+width(), _y+19, _x+width()-3, _y+22 ); + + // Double circules + p.drawEllipse( _x, _y+24, 16, 16 ); + p.drawEllipse( _x+8, _y+24, 16, 16 ); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/eccurrentsource.h b/src/electronics/components/eccurrentsource.h new file mode 100644 index 0000000..6332eba --- /dev/null +++ b/src/electronics/components/eccurrentsource.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECCURRENTSOURCE_H +#define ECCURRENTSOURCE_H + +#include "component.h" + +/** +@short Fixed current source +@author David Saxton +*/ +class ECCurrentSource : public Component +{ +public: + ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCurrentSource(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + CurrentSource *m_currentSource; +}; + +#endif diff --git a/src/electronics/components/ecdiode.cpp b/src/electronics/components/ecdiode.cpp new file mode 100644 index 0000000..1d63bce --- /dev/null +++ b/src/electronics/components/ecdiode.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2003,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 "diode.h" +#include "ecdiode.h" +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include + +Item* ECDiode::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDiode( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDiode::libraryItem() +{ + return new LibraryItem( + "ec/diode", + i18n("Diode"), + i18n("Discrete"), + "diode.png", + LibraryItem::lit_component, + ECDiode::construct ); +} + +ECDiode::ECDiode( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "diode" ) +{ + m_name = i18n("Diode"); + m_desc = i18n("Allows current to flow in the direction indicated by the arrow when a certain voltage difference has been reached."); + + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_diode = createDiode( m_pNNode[0], m_pPNode[0] ); + + DiodeSettings ds; // it will have the default properties that we use + + createProperty( "I_S", Variant::Type::Double ); + property("I_S")->setCaption("Saturation Current"); + property("I_S")->setUnit("A"); + property("I_S")->setMinValue(1e-20); + property("I_S")->setMaxValue(1e-0); + property("I_S")->setValue( ds.I_S ); + property("I_S")->setAdvanced(true); + + createProperty( "N", Variant::Type::Double ); + property("N")->setCaption( i18n("Emission Coefficient") ); + property("N")->setMinValue(1e0); + property("N")->setMaxValue(1e1); + property("N")->setValue( ds.N ); + property("N")->setAdvanced(true); + + createProperty( "V_B", Variant::Type::Double ); + property("V_B")->setCaption( i18n("Breakdown Voltage") ); + property("V_B")->setUnit("V"); + property("V_B")->setMinAbsValue(1e-5); + property("V_B")->setMaxValue(1e10); + property("V_B")->setValue( ds.V_B ); + property("V_B")->setAdvanced(true); + +// createProperty( "R", Variant::Type::Double ); +// property("R")->setCaption( i18n("Series Resistance") ); +// property("R")->setUnit( QChar(0x3a9) ); +// property("R")->setMinValue(1e-5); +// property("R")->setMaxValue(1e0); +// property("R")->setValue( ds.R ); +// property("R")->setAdvanced(true); +} + + +ECDiode::~ECDiode() +{ +} + + +void ECDiode::dataChanged() +{ + DiodeSettings ds; + + ds.I_S = dataDouble("I_S"); + ds.V_B = dataDouble("V_B"); + ds.N = dataDouble("N"); +// ds.R = dataDouble("R"); + + m_diode->setDiodeSettings( ds ); +} + + +void ECDiode::drawShape( QPainter & p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + QPointArray pa(3); + pa[0] = QPoint( 8, 0 ); + pa[1] = QPoint( -8, -8 ); + pa[2] = QPoint( -8, 8 ); + pa.translate( _x, _y ); + p.drawPolygon(pa); + p.drawPolyline(pa); + + p.drawLine( _x+8, _y-8, _x+8, _y+8 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/ecdiode.h b/src/electronics/components/ecdiode.h new file mode 100644 index 0000000..fa8d034 --- /dev/null +++ b/src/electronics/components/ecdiode.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003,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. * + ***************************************************************************/ + +#ifndef ECDIODE_H +#define ECDIODE_H + +#include "component.h" + +/** +@short Simple diode +@author David Saxton +*/ +class ECDiode : public Component +{ +public: + ECDiode( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDiode(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void drawShape( QPainter & p ); + void dataChanged(); + Diode *m_diode; +}; + +#endif diff --git a/src/electronics/components/ecfixedvoltage.cpp b/src/electronics/components/ecfixedvoltage.cpp new file mode 100644 index 0000000..06eb707 --- /dev/null +++ b/src/electronics/components/ecfixedvoltage.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecfixedvoltage.h" + +#include "ecnode.h" +#include "voltagepoint.h" +#include "libraryitem.h" + +#include +#include + +Item* ECFixedVoltage::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECFixedVoltage( (ICNDocument*)itemDocument, newItem, id ); +} +LibraryItem* ECFixedVoltage::libraryItem() +{ + return new LibraryItem( + "ec/fixed_voltage", + i18n("Fixed Voltage"), + i18n("Sources"), + "voltage.png", + LibraryItem::lit_component, + ECFixedVoltage::construct ); +} + +ECFixedVoltage::ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "fixed_voltage" ) +{ + m_name = i18n("Fixed Voltage"); + m_desc = i18n("Provides a fixed voltage point to connect components to."); + setSize( -8, -8, 16, 16 ); + + init1PinRight(); + m_voltagePoint = createVoltagePoint( m_pPNode[0], 5.0 ); + + addDisplayText( "voltage", QRect( -24, -20, width()+32, 12 ), "" ); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setUnit("V"); + property("voltage")->setCaption( i18n("Voltage") ); + property("voltage")->setMinValue(-1e15); + property("voltage")->setMaxValue(1e15); + property("voltage")->setValue(5.0); +} + +ECFixedVoltage::~ECFixedVoltage() +{ +} + +void ECFixedVoltage::dataChanged() +{ + const double voltage = dataDouble("voltage"); + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); + m_voltagePoint->setVoltage(voltage); +} + +void ECFixedVoltage::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = int(x()); + int _y = int(y()); + p.drawEllipse( _x-4, _y-4, 8, 8 ); + p.setPen( m_pPNode[0]->isSelected() ? m_selectedCol : Qt::black ); + p.drawLine( _x+4, _y, _x+8, _y ); + deinitPainter(p); +} + diff --git a/src/electronics/components/ecfixedvoltage.h b/src/electronics/components/ecfixedvoltage.h new file mode 100644 index 0000000..ba20358 --- /dev/null +++ b/src/electronics/components/ecfixedvoltage.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECFIXEDVOLTAGE_H +#define ECFIXEDVOLTAGE_H + +#include "component.h" + +/** +@short Fixed voltage source +@author David Saxton +*/ +class ECFixedVoltage : public Component +{ +public: + ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECFixedVoltage(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); + void dataChanged(); + VoltagePoint *m_voltagePoint; +}; + +#endif diff --git a/src/electronics/components/ecground.cpp b/src/electronics/components/ecground.cpp new file mode 100644 index 0000000..efbfc41 --- /dev/null +++ b/src/electronics/components/ecground.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecground.h" + +#include "ecnode.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +Item* ECGround::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECGround( (ICNDocument*)itemDocument, newItem, id ); +} +LibraryItem* ECGround::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/ground"), + i18n("Ground (0V)"), + i18n("Sources"), + "ground.png", + LibraryItem::lit_component, + ECGround::construct ); +} + +ECGround::ECGround( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ground" ) +{ + m_name = i18n("Ground"); + m_desc = i18n("Ground (0V) point"); + setSize( -8, -8, 16, 16 ); + init1PinRight(); + m_pPNode[0]->pin()->setGroundType( Pin::gt_always ); + setAngleDegrees(270); +} + +ECGround::~ECGround() +{ +} + +void ECGround::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + QPen pen; + pen.setWidth(2); + pen.setColor( p.pen().color() ); + p.setPen(pen); + p.drawLine( _x+15, _y, _x+15, _y+16 ); + p.drawLine( _x+10, _y+3, _x+10, _y+13 ); + p.drawLine( _x+5, _y+6, _x+5, _y+10 ); + deinitPainter(p); +} + + + diff --git a/src/electronics/components/ecground.h b/src/electronics/components/ecground.h new file mode 100644 index 0000000..0cf97bc --- /dev/null +++ b/src/electronics/components/ecground.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECGROUND_H +#define ECGROUND_H + +#include "component.h" + +/** +@short Fixed voltage source +@author David Saxton +*/ +class ECGround : public Component +{ +public: + ECGround( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECGround(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/electronics/components/eckeypad.cpp b/src/electronics/components/eckeypad.cpp new file mode 100644 index 0000000..89d2659 --- /dev/null +++ b/src/electronics/components/eckeypad.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** + * Copyright (C) 2003,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 "canvasitemparts.h" +#include "eckeypad.h" +#include "libraryitem.h" +#include "switch.h" + +#include "ecnode.h" +#include + +Item* ECKeyPad::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECKeyPad( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECKeyPad::libraryItem() +{ + return new LibraryItem( + QString("ec/keypad"), + i18n("Keypad"), + i18n("Switches"), + "keypad.png", + LibraryItem::lit_component, + ECKeyPad::construct ); +} + +const QString text[4][9] = + { { "1","2","3","A","E","I","M","Q","U" }, + { "4","5","6","B","F","J","N","R","V" }, + { "7","8","9","C","G","K","O","S","W" }, + { "*","0","#","D","H","L","P","T","X" } }; + +ECKeyPad::ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "keypad" ) +{ + m_name = i18n("Keypad"); + m_desc = i18n("Provides a numeric array of Push-to-Make switches, with 4 rows and a configurable number of columns."); + + createProperty( "useToggles", Variant::Type::Bool ); + property("useToggles")->setCaption( i18n("Use Toggles") ); + property("useToggles")->setValue(false); + + createProperty( "numCols", Variant::Type::Int ); + property("numCols")->setCaption( i18n("Columns") ); + property("numCols")->setMinValue(3); + property("numCols")->setMaxValue(9); + property("numCols")->setValue(3); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + for ( int i = 0; i < 4; i++ ) + createPin( 0, -32+i*24, 0, QString("row_%1").arg(QString::number(i)) ); + + m_numCols = 0; +} + + +ECKeyPad::~ECKeyPad() +{ +} + + +QString ECKeyPad::buttonID( int row, int col ) const +{ + return QString("b_%1_%2").arg(QString::number(row)).arg(QString::number(col)); +} + + +int ECKeyPad::sideLength( unsigned numButtons ) const +{ + return 8 + 24*numButtons; +} + + +void ECKeyPad::dataChanged() +{ + initPins( dataInt("numCols") ); + + bool useToggle = dataBool("useToggles"); + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = 0; j < m_numCols; j++ ) + { + button( buttonID(i,j) )->setToggle(useToggle); + m_switch[i][j]->setBounce( bounce, bouncePeriod_ms ); + } + } +} + + +void ECKeyPad::initPins( unsigned numCols ) +{ + if ( numCols < 3 ) + numCols = 3; + else if ( numCols > 9 ) + numCols = 9; + + if ( numCols == m_numCols ) + return; + + int w = sideLength(numCols); + int h = sideLength(4); + setSize( -int(w/16)*8, -int(h/16)*8, w, h, true ); + + if ( numCols > m_numCols ) + { + // Adding columns + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = m_numCols; j < numCols; j++ ) + addButton( buttonID(i,j), QRect( 0, 0, 20, 20 ), text[i][j] ); + } + + ECNode * cols[numCols]; + + for ( unsigned j = m_numCols; j < numCols; j++ ) + cols[j] = createPin( 0, 64, 270, "col_" + QString::number(j) ); + + for ( unsigned i = 0; i < 4; i++ ) + { + ECNode * row = ecNodeWithID("row_"+QString::number(i)); + for ( unsigned j = m_numCols; j < numCols; j++ ) + m_switch[i][j] = createSwitch( cols[j], row, true ); + } + } + else + { + // Remove columns + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = numCols; j < m_numCols; j++ ) + removeWidget( buttonID(i,j) ); + } + + for ( unsigned j = numCols; j < m_numCols; j++ ) + removeNode( "col_" + QString::number(j) ); + + for ( unsigned i = 0; i < 4; i++ ) + { + for ( unsigned j = m_numCols; j < numCols; j++ ) + removeSwitch( m_switch[i][j] ); + } + } + + //BEGIN Update Positions + m_numCols = numCols; + + for ( int i = 0; i < 4; i++ ) + { + for ( int j = 0; j < int(m_numCols); j++ ) + { + widgetWithID( buttonID(i,j) )->setOriginalRect( + QRect( offsetX() + 6 + 24*j, offsetY() + 6 + 24*i, 20, 20 ) ); + } + } + + for ( int i = 0; i < 4; i++ ) + m_nodeMap["row_" + QString::number(i)].x = width()+offsetX(); + + for ( int j = 0; j < int(m_numCols); j++ ) + m_nodeMap["col_" + QString::number(j)].x = 24*j+offsetX()+16; + + updateAttachedPositioning(); + //END Update Positions +} + + +void ECKeyPad::buttonStateChanged( const QString &id, bool state ) +{ + if ( !id.startsWith("b_") ) + return; + + QStringList tags = QStringList::split( '_', id ); + const int i = tags[1].toInt(); + const int j = tags[2].toInt(); + m_switch[i][j]->setState( state ? Switch::Closed : Switch::Open ); +} diff --git a/src/electronics/components/eckeypad.h b/src/electronics/components/eckeypad.h new file mode 100644 index 0000000..18a497c --- /dev/null +++ b/src/electronics/components/eckeypad.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2003,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. * + ***************************************************************************/ + +#ifndef ECKEYPAD_H +#define ECKEYPAD_H + +#include "component.h" + +/** +@short 4x3 PTM Keypad +@author David Saxton +*/ +class ECKeyPad : public Component +{ + public: + ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECKeyPad(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual bool canFlip() const { return true; } + + protected: + virtual void dataChanged(); + void initPins( unsigned numCols); + QString buttonID( int row, int col ) const; + int sideLength( unsigned numButtons ) const; + + Switch *m_switch[4][11]; + unsigned m_numCols; +}; + +#endif diff --git a/src/electronics/components/ecled.cpp b/src/electronics/components/ecled.cpp new file mode 100644 index 0000000..c865de6 --- /dev/null +++ b/src/electronics/components/ecled.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include + +Item* ECLed::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECLed( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECLed::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/led"), + i18n("LED"), + i18n("Outputs"), + "led.png", + LibraryItem::lit_component, + ECLed::construct + ); +} + +ECLed::ECLed( ICNDocument *icnDocument, bool newItem, const char *id ) + : ECDiode( icnDocument, newItem, (id) ? id : "led" ) +{ + m_bDynamicContent = true; + m_name = i18n("LED"); + m_desc = i18n("Light Emitting Diode"); + setSize( -8, -16, 24, 24, true ); + avg_brightness = 255; + lastUpdatePeriod = 0.; + r=g=b=0; + last_brightness = 255; + + createProperty( "0-color", Variant::Type::Color ); + property("0-color")->setCaption( i18n("Color") ); + property("0-color")->setColorScheme( ColorCombo::LED ); +} + +ECLed::~ECLed() +{ +} + +void ECLed::dataChanged() +{ + QColor color = dataColor("0-color"); + r = color.red(); + g = color.green(); + b = color.blue(); + r /= 0x100; + g /= 0x100; + b /= 0x100; +} + +void ECLed::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + avg_brightness += brightness(m_diode->current())*interval; + lastUpdatePeriod += interval; +} + +void ECLed::drawShape( QPainter &p ) +{ + int _x = int(x()); + int _y = int(y()); + + initPainter(p); + + //BEGIN draw "Diode" part + uint _b; + if ( lastUpdatePeriod == 0. ) + _b = last_brightness; + else + { + _b = (uint)(avg_brightness/lastUpdatePeriod); + last_brightness = _b; + } + avg_brightness = 0.; + lastUpdatePeriod = 0.; + + p.setBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) ); + + QPointArray pa(3); + pa[0] = QPoint( 8, 0 ); + pa[1] = QPoint( -8, -8 ); + pa[2] = QPoint( -8, 8 ); + pa.translate( _x, _y ); + p.drawPolygon(pa); + p.drawPolyline(pa); + + p.drawLine( _x+8, _y-8, _x+8, _y+8 ); + //END draw "Diode" part + + + + //BEGIN draw "Arrows" part + p.drawLine( _x+7, _y-10, _x+10, _y-13 ); // Tail of left arrow + p.drawLine( _x+10, _y-13, _x+8, _y-13 ); // Left edge of left arrow tip + p.drawLine( _x+10, _y-13, _x+10, _y-11 ); // Right edge of left arrow tip + + p.drawLine( _x+10, _y-7, _x+13, _y-10 ); // Tail of right arrow + p.drawLine( _x+13, _y-10, _x+11, _y-10 ); // Left edge of right arrow tip + p.drawLine( _x+13, _y-10, _x+13, _y-8 ); // Right edge of right arrow tip + + p.drawLine( _x+8, _y-13, _x+13, _y-8 ); // Diagonal line that forms base of both arrow tips + //END draw "Arrows" part1 + + + deinitPainter(p); +} + + +uint ECLed::brightness( double i ) +{ + if ( i > 0.018 ) return 0; + if ( i < 0.002 ) return 255; + return (uint)(255*(1-((i-0.002)/0.016))); +} + diff --git a/src/electronics/components/ecled.h b/src/electronics/components/ecled.h new file mode 100644 index 0000000..ce24598 --- /dev/null +++ b/src/electronics/components/ecled.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECLED_H +#define ECLED_H + +#include "component.h" +#include "ecdiode.h" + +/** +@short Simulates a LED +@author David Saxton +*/ +class ECLed : public ECDiode +{ +public: + ECLed( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECLed(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + /** + * Returns the brightness for the given current, from 255 (off) -> 0 (on) + */ + static uint brightness( double i ); + + virtual void dataChanged(); + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + + double r, g, b; + + double avg_brightness; + uint last_brightness; + double lastUpdatePeriod; +}; + +#endif diff --git a/src/electronics/components/ecopamp.cpp b/src/electronics/components/ecopamp.cpp new file mode 100644 index 0000000..dbb7457 --- /dev/null +++ b/src/electronics/components/ecopamp.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * 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 "ecopamp.h" + +#include "ecnode.h" +#include "libraryitem.h" + +#include +#include + +Item* ECOpAmp::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECOpAmp( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ECOpAmp::libraryItem() +{ + return new LibraryItem( + "ec/opamp", + i18n("Op Amp"), + i18n("Integrated Circuits"), + "opamp.png", + LibraryItem::lit_component, + ECOpAmp::construct ); +} + + +ECOpAmp::ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "opamp" ) +{ + m_name = i18n("Operational Amplifier"); + m_desc = i18n("Ideal amplifier"); + + QPointArray pa(3); + pa[0] = QPoint( -16, -16 ); + pa[1] = QPoint( 16, 0 ); + pa[2] = QPoint( -16, 16 ); + setItemPoints( pa, true ); + + init2PinLeft( -8, 8 ); + init1PinRight(); + createOpAmp( m_pNNode[0], m_pPNode[0], m_pNNode[1] ); +} + + +ECOpAmp::~ECOpAmp() +{ +} + + +void ECOpAmp::drawShape( QPainter & p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + QPointArray pa(3); + pa[0] = QPoint( _x-16, _y-16 ); + pa[1] = QPoint( _x+16, _y ); + pa[2] = QPoint( _x-16, _y+16 ); + + p.drawPolygon(pa); + p.drawPolyline(pa); + + // Plus symbol + p.drawLine( _x-9, _y-8, _x-9, _y-2 ); + p.drawLine( _x-12, _y-5, _x-6, _y-5 ); + + // Minus symbol + p.drawLine( _x-11, _y+6, _x-7, _y+6 ); + + deinitPainter(p); +} + + diff --git a/src/electronics/components/ecopamp.h b/src/electronics/components/ecopamp.h new file mode 100644 index 0000000..6b6b147 --- /dev/null +++ b/src/electronics/components/ecopamp.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECOPAMP_H +#define ECOPAMP_H + +#include "component.h" + +/** +@short Operational Amplifier +@author David Saxton +*/ +class ECOpAmp : public Component +{ + public: + ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECOpAmp(); + + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void drawShape( QPainter & p ); +}; + +#endif diff --git a/src/electronics/components/ecpotentiometer.cpp b/src/electronics/components/ecpotentiometer.cpp new file mode 100644 index 0000000..db0fedd --- /dev/null +++ b/src/electronics/components/ecpotentiometer.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "canvasitemparts.h" +#include "ecnode.h" +#include "ecpotentiometer.h" +#include "libraryitem.h" +#include "resistance.h" + +#include +#include +#include + +Item* ECPotentiometer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPotentiometer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPotentiometer::libraryItem() +{ + return new LibraryItem( + "ec/potentiometer", + i18n("Potentiometer"), + i18n("Discrete"), + "potentiometer.png", + LibraryItem::lit_component, + ECPotentiometer::construct ); +} + +ECPotentiometer::ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "potentiometer" ) +{ + m_name = i18n("Potentiometer"); + m_desc =i18n("Consists of a resistor connected to the end pins, with a central pin connected at an adjustable point along the resistor"); + setSize( -16, -16, 40, 32 ); + + m_p1 = createPin( 32, 0, 180, "p1" ); + + m_sliderProp = 0.0; + m_resistance = 5000.; + m_r1 = createResistance( createPin( -8, -24, 90, "n1" ), m_p1, 1. ); + m_r2 = createResistance( createPin( -8, 24, 270, "n2" ), m_p1, 1. ); + + Slider * s = addSlider( "slider", 0, 100, 5, 50, Qt::Vertical, QRect( 0, -16, 16, 32 ) ); + m_pSlider = static_cast(s->widget()); + + createProperty( "resistance", Variant::Type::Double ); + property("resistance")->setCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setMinValue(1e-6); + property("resistance")->setValue(1e5); + + addDisplayText( "res", QRect( -56, -8, 40, 16 ), "" ); +} + +ECPotentiometer::~ECPotentiometer() +{ +} + +void ECPotentiometer::dataChanged() +{ + m_resistance = dataDouble("resistance"); + + QString display = QString::number( m_resistance / getMultiplier(m_resistance), 'g', 3 ) + getNumberMag(m_resistance) + QChar(0x3a9); + setDisplayText( "res", display ); + + sliderValueChanged( "slider", slider("slider")->value() ); +} + +void ECPotentiometer::sliderValueChanged( const QString &id, int newValue ) +{ + if ( id != "slider" ) + return; + + m_sliderProp = (newValue-50.0)/100.0; + + m_r1->setResistance( m_resistance*(double)newValue/100. ); + m_r2->setResistance( m_resistance*(double)(100.-newValue)/100. ); +} + +void ECPotentiometer::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = int(x()); + int _y = int(y()); + + p.drawRect( _x-14, _y-16, 12, 32 ); + + QPointArray pa(3); + pa[0] = QPoint( 0, 0 ); + pa[1] = QPoint( 4, -3 ); + pa[2] = QPoint( 4, 3 ); + + int space = m_pSlider->style().pixelMetric( QStyle::PM_SliderSpaceAvailable, m_pSlider ); + int base_y = _y + (( angleDegrees() == 0 || angleDegrees() == 270 ) ? 1 : -1) * int( space * m_sliderProp ); + + pa.translate( _x+16, base_y ); + + QColor c = m_p1->isSelected() ? m_selectedCol : black; + + p.setPen(c); + p.setBrush(c); + p.drawPolygon(pa); + + p.drawLine( _x+20, base_y, _x+24, base_y ); + p.drawLine( _x+24, base_y, _x+24, _y ); + + deinitPainter(p); +} + + + diff --git a/src/electronics/components/ecpotentiometer.h b/src/electronics/components/ecpotentiometer.h new file mode 100644 index 0000000..e7ca83b --- /dev/null +++ b/src/electronics/components/ecpotentiometer.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef ECPOTENTIOMETER_H +#define ECPOTENTIOMETER_H + +#include "component.h" + +class QSlider; + +/** +@short Potentiometer +@author David Saxton +*/ +class ECPotentiometer : public Component +{ +public: + ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPotentiometer(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void sliderValueChanged( const QString &id, int newValue ); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + + ECNode * m_p1; + Resistance *m_r1, *m_r2; + double m_resistance; + double m_sliderProp; + QSlider * m_pSlider; +}; +#endif diff --git a/src/electronics/components/ecresistor.cpp b/src/electronics/components/ecresistor.cpp new file mode 100644 index 0000000..e4ee7a3 --- /dev/null +++ b/src/electronics/components/ecresistor.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "ecresistor.h" + +#include "libraryitem.h" +#include "resistance.h" + +#include +#include + +Item* ECResistor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECResistor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECResistor::libraryItem() +{ + return new LibraryItem( + "ec/resistor", + i18n("Resistor"), + i18n("Discrete"), + "resistor.png", + LibraryItem::lit_component, + ECResistor::construct ); +} + +ECResistor::ECResistor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "resistor" ) +{ + m_name = i18n("Resistor"); + m_desc = i18n("Limits the flow of current, obeying Ohms Law"); + setSize( -16, -8, 32, 16 ); + + init1PinLeft(); + init1PinRight(); + m_resistance = createResistance( m_pPNode[0], m_pNNode[0], 1. ); + + createProperty( "resistance", Variant::Type::Double ); + property("resistance")->setCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setValue(1e4); + property("resistance")->setMinValue(1e-6); + + addDisplayText( "res", QRect( -16, -22, 32, 12 ), "", false ); +} + +ECResistor::~ECResistor() +{ +} + +void ECResistor::dataChanged() +{ + double resistance = dataDouble("resistance"); + + QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9); + setDisplayText( "res", display ); + + m_resistance->setResistance(resistance); +} + +void ECResistor::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawRect( (int)x()-16, (int)y()-6, width(), 12 ); + deinitPainter(p); +} + + diff --git a/src/electronics/components/ecresistor.h b/src/electronics/components/ecresistor.h new file mode 100644 index 0000000..17e799e --- /dev/null +++ b/src/electronics/components/ecresistor.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECRESISTOR_H +#define ECRESISTOR_H + +#include "component.h" + +/** +@short Simple resistor +@author David Saxton +*/ +class ECResistor : public Component +{ + public: + ECResistor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECResistor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + Resistance * m_resistance; +}; + +#endif diff --git a/src/electronics/components/ecsevensegment.cpp b/src/electronics/components/ecsevensegment.cpp new file mode 100644 index 0000000..ec35776 --- /dev/null +++ b/src/electronics/components/ecsevensegment.cpp @@ -0,0 +1,210 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "ecsevensegment.h" +#include "libraryitem.h" +#include "simulator.h" + +#include +#include +#include + +Item* ECSevenSegment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSevenSegment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSevenSegment::libraryItem() +{ + return new LibraryItem( + "ec/seven_segment", + i18n("Seven Segment"), + i18n("Outputs"), + "seven_segment.png", + LibraryItem::lit_component, + ECSevenSegment::construct ); +} + +ECSevenSegment::ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "seven_segment" ) +{ + m_name = i18n("Seven Segment LED"); + m_desc = i18n("A seven segment display with a decimal point. This can be configured to either have a common cathode or a common anode."); + m_bDynamicContent = true; + + QStringList pins = QStringList::split( ',', "g,f,e,d,"+QString(QChar(0xB7))+",c,b,a" ); + + createProperty( "0-color", Variant::Type::Color ); + property("0-color")->setCaption( i18n("Color") ); + property("0-color")->setColorScheme( ColorCombo::LED ); + + createProperty( "diode-polarity", Variant::Type::Select ); + property("diode-polarity")->setCaption( i18n("Configuration") ); + property("diode-polarity")->setAllowed( QStringList::split(',',"Common Cathode,Common Anode") ); + property("diode-polarity")->setValue("Common Cathode"); + + for ( int i=0; i<8; i++ ) + { + m_diodes[i] = 0L; + m_nodes[i] = 0L; + avg_brightness[i] = 0.; + last_brightness[i] = 255; + } + m_nNode = 0L; + + lastUpdatePeriod = 0.; + + initDIPSymbol( pins, 64 ); + initDIP(pins); + + m_nNode = createPin( width()/2+offsetX(), height()+8+offsetY(), 270, "-v" ); + + for ( int i=0; i<7; i++ ) + m_nodes[i] = ecNodeWithID( QChar('a'+i) ); + + m_nodes[7] = ecNodeWithID(QChar(0xB7)); + + m_bCommonCathode = false; // Force update +} + + +ECSevenSegment::~ECSevenSegment() +{ +} + + +void ECSevenSegment::dataChanged() +{ + QColor color = dataColor("0-color"); + r = color.red(); + g = color.green(); + b = color.blue(); + r /= 0x100; + g /= 0x100; + b /= 0x100; + + bool commonCathode = dataString("diode-polarity") == "Common Cathode"; + if ( commonCathode != m_bCommonCathode ) + { + m_bCommonCathode = commonCathode; + for ( int i=0; i<7; i++ ) + { + removeElement( m_diodes[i], false ); + if (commonCathode) + m_diodes[i] = createDiode( m_nodes[i], m_nNode ); + else + m_diodes[i] = createDiode( m_nNode, m_nodes[i] ); + } + + removeElement( m_diodes[7], false ); + if (commonCathode) + m_diodes[7] = createDiode( m_nodes[7], m_nNode ); + else + m_diodes[7] = createDiode( m_nNode, m_nodes[7] ); + } + + update(); +} + + +void ECSevenSegment::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + + for ( int i=0; i<8; i++ ) { + avg_brightness[i] += ECLed::brightness( m_diodes[i]->current() )*interval; + } + + lastUpdatePeriod += interval; +} + +void ECSevenSegment::drawShape( QPainter &p ) +{ + CNItem::drawShape(p); + + initPainter(p); + + const int _width = 20; + const int _height = 32; + + const int x1 = (int)x()+offsetX() + (width()-_width)/2 - 1; + const int x2 = x1 + _width; + const int y1 = (int)y()+offsetY() + (height()-_height)/2; + const int y2 = y1 + _height/2; + const int y3 = y1 + _height; + const int ds = 2; // "Slope" + +// QPen pen; +// pen.setWidth(2); +// pen.setCapStyle(Qt::RoundCap); +// p.setPen(pen); + + if ( lastUpdatePeriod != 0. ) + { + for ( uint i=0; i<8; ++i ) + { + last_brightness[i] = (uint)(avg_brightness[i]/lastUpdatePeriod); + } + } + + double _b; + + // Top + _b = last_brightness[0]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+3+ds, y1+0, x2-3+ds, y1+0 ); + + // Top right + _b = last_brightness[1]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2+0+ds, y1+3, x2+0, y2-3 ); + + // Bottom right + _b = last_brightness[2]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2+0, y2+3, x2+0-ds, y3-3 ); + + // Bottom + _b = last_brightness[3]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x2-3-ds, y3+0, x1+3-ds, y3+0 ); + + // Bottom left + _b = last_brightness[4]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+0-ds, y3-3, x1+0, y2+3 ); + + // Top left + _b = last_brightness[5]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+0, y2-3, x1+0+ds, y1+3 ); + + // Middle + _b = last_brightness[6]; + p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) ); + p.drawLine( x1+3, y2+0, x2-3, y2+0 ); + + // Decimal point + _b = last_brightness[7]; + p.setBrush( QBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) ) ); + p.setPen( Qt::NoPen ); + p.drawPie( x2+3, y3-2, 3, 3, 0, 16*360 ); + + lastUpdatePeriod = 0.; + for ( uint i=0; i<8; ++i ) { + avg_brightness[i] = 0.; + } + + deinitPainter(p); +} diff --git a/src/electronics/components/ecsevensegment.h b/src/electronics/components/ecsevensegment.h new file mode 100644 index 0000000..7041c9a --- /dev/null +++ b/src/electronics/components/ecsevensegment.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef ECSEVENSEGMENT_H +#define ECSEVENSEGMENT_H + +#include "component.h" + +class Diode; +class ECNode; + +/** +@short Seven segment display component +@author David Saxton +*/ +class ECSevenSegment : public Component +{ +public: + ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSevenSegment(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + + bool m_bCommonCathode; + double lastUpdatePeriod; + double avg_brightness[8]; + uint last_brightness[8]; + Diode *m_diodes[8]; + ECNode *m_nodes[8]; + ECNode *m_nNode; + double r, g, b; +}; + +#endif diff --git a/src/electronics/components/ecsignallamp.cpp b/src/electronics/components/ecsignallamp.cpp new file mode 100644 index 0000000..c7034f7 --- /dev/null +++ b/src/electronics/components/ecsignallamp.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "ecnode.h" +#include "ecsignallamp.h" +#include "element.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +Item* ECSignalLamp::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSignalLamp( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSignalLamp::libraryItem() +{ + return new LibraryItem( + QString("ec/signal_lamp"), + i18n("Signal Lamp"), + i18n("Outputs"), + "signal_lamp.png", + LibraryItem::lit_component, + ECSignalLamp::construct ); +} + +ECSignalLamp::ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "signal_lamp" ) +{ + m_name = i18n("Signal Lamp"); + m_desc = i18n("A simple filament signal lamp, with a 100 ohms series resistance."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + createResistance( m_pPNode[0], m_pNNode[0], 100. ); + + advanceSinceUpdate = 0; + avgPower = 0.; + m_bDynamicContent = true; +} + +ECSignalLamp::~ECSignalLamp() +{ +} + +void ECSignalLamp::stepNonLogic() +{ + const double voltage = m_pPNode[0]->pin()->voltage()-m_pNNode[0]->pin()->voltage(); + avgPower = QABS(avgPower*advanceSinceUpdate + (voltage*voltage/100))/++advanceSinceUpdate; +} + +void ECSignalLamp::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x()); + int _y = int(y()); + + // Calculate the brightness as a linear function of power, bounded below by + // 25 milliWatts and above by 500 milliWatts. + int brightness = (avgPower<0.025) ? 255 : ((avgPower>0.5) ? 0 : (int)(255*(1-((avgPower-0.025)/0.475)))); + advanceSinceUpdate = 0; + + p.setBrush( QColor( 255, 255, brightness ) ); + p.drawEllipse( _x-8, _y-8, 16, 16 ); + + // 2*sqrt(2) = 2.828427125... + int pos = 8 - int(16/2.828); + + p.drawLine( _x-8+pos, _y-8+pos, _x+8-pos, _y+8-pos ); + p.drawLine( _x+8-pos, _y-8+pos, _x-8+pos, _y+8-pos ); + + deinitPainter(p); +} diff --git a/src/electronics/components/ecsignallamp.h b/src/electronics/components/ecsignallamp.h new file mode 100644 index 0000000..e56d724 --- /dev/null +++ b/src/electronics/components/ecsignallamp.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef ECSIGNALLAMP_H +#define ECSIGNALLAMP_H + +#include "component.h" + +class Resistance; + +/** +@short Signal Lamp - glows when current flows +@author David Saxton +*/ +class ECSignalLamp : public Component +{ +public: + ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSignalLamp(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + +private: + void drawShape( QPainter &p ); + double avgPower; + uint advanceSinceUpdate; +}; + +#endif diff --git a/src/electronics/components/ecsubcircuit.cpp b/src/electronics/components/ecsubcircuit.cpp new file mode 100644 index 0000000..a69e720 --- /dev/null +++ b/src/electronics/components/ecsubcircuit.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + * 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 "canvasitemparts.h" +#include "circuitdocument.h" +#include "ecsubcircuit.h" +#include "node.h" +#include "libraryitem.h" +#include "subcircuits.h" + +#include +#include +#include + +Item* ECSubcircuit::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSubcircuit( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSubcircuit::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/subcircuit"), + QString::null, + QString::null, + QString::null, + LibraryItem::lit_subcircuit, + ECSubcircuit::construct ); +} + +ECSubcircuit::ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "subcircuit" ) +{ + m_name = i18n("Subcircuit"); + + createProperty( "id", Variant::Type::Int ); + property("id")->setMinValue(1); + property("id")->setMaxValue(1<<15); + property("id")->setValue(1); + property("id")->setHidden(true); +} + + +ECSubcircuit::~ECSubcircuit() +{ +} + + +void ECSubcircuit::removeItem() +{ + emit subcircuitDeleted(); + Component::removeItem(); +} + + +void ECSubcircuit::setNumExtCon( unsigned numExtCon ) +{ + m_conNames.resize(numExtCon); + + // Remove old pins + const NodeMap::iterator nodeMapEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it ) + { + p_icnDocument->appendDeleteList( p_icnDocument->nodeWithID(it.data().id) ); + } + p_icnDocument->flushDeleteList(); + m_nodeMap.clear(); + + QStringList pins; + for ( unsigned i=0; i m_conNames.size() ) + return; + + m_conNames[numId] = name; +} + + +void ECSubcircuit::doneSCInit() +{ + QStringList pins; + for ( unsigned i = 0; i < m_conNames.size(); ++i ) + pins << m_conNames[i]; + initDIPSymbol( pins, 80 ); +} + + +void ECSubcircuit::drawShape( QPainter &p ) +{ + Component::drawShape(p); +} + + +#include "ecsubcircuit.moc" + + + diff --git a/src/electronics/components/ecsubcircuit.h b/src/electronics/components/ecsubcircuit.h new file mode 100644 index 0000000..eaf21ec --- /dev/null +++ b/src/electronics/components/ecsubcircuit.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef ECSUBCIRCUIT_H +#define ECSUBCIRCUIT_H + +#include + +#include + +/** +"Container" component for subcircuits +@author David Saxton +*/ +class ECSubcircuit : public Component +{ +Q_OBJECT +public: + ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSubcircuit(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + /** + * Create numExtCon nodes, deleting any old ones + */ + void setNumExtCon( unsigned numExtCon ); + /** + * Give the connecting node at position numId the given name + */ + void setExtConName( unsigned numId, const QString & name ); + /** + * Called from SubcircuitData once the subcircuit has been fully attached + */ + void doneSCInit(); + +public slots: + virtual void removeItem(); + +signals: + /** + * Emitted when the current subcircuit is deleted + */ + void subcircuitDeleted(); + +protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + QValueVector m_conNames; +}; + +#endif diff --git a/src/electronics/components/ecvoltagesignal.cpp b/src/electronics/components/ecvoltagesignal.cpp new file mode 100644 index 0000000..c338f36 --- /dev/null +++ b/src/electronics/components/ecvoltagesignal.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "ecnode.h" +#include "ecvoltagesignal.h" +#include "libraryitem.h" +#include "pin.h" +#include "simulator.h" +#include "voltagesignal.h" + +#include +#include + +const double conductance = 1e5; // Internal resistance + +Item* ECVoltageSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVoltageSignal( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVoltageSignal::libraryItem() +{ + return new LibraryItem( + QString("ec/voltage_signal"), + i18n("Voltage Signal"), + i18n("Sources"), + "voltagesignal.png", + LibraryItem::lit_component, + ECVoltageSignal::construct ); +} + +ECVoltageSignal::ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "voltage_signal" ) +{ + m_name = i18n("Voltage Signal"); + m_desc = i18n("Provides a variety of voltage signals."); + setSize( -8, -8, 16, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_medium ); + m_voltageSignal = createVoltageSignal( m_pNNode[0], m_pPNode[0], 0. ); + m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. ); + + createProperty( "frequency", Variant::Type::Double ); + property("frequency")->setCaption( i18n("Frequency") ); + property("frequency")->setUnit("Hz"); + property("frequency")->setMinValue(1e-9); + property("frequency")->setMaxValue(1e3); + property("frequency")->setValue(50.0); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setCaption( i18n("Voltage Range") ); + property("voltage")->setUnit("V"); + property("voltage")->setMinValue(-1e12); + property("voltage")->setMaxValue(1e12); + property("voltage")->setValue(5.0); + + addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" ); + addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" ); +} + + +ECVoltageSignal::~ECVoltageSignal() +{ +} + +void ECVoltageSignal::dataChanged() +{ + const double voltage = dataDouble("voltage"); + const double frequency = dataDouble("frequency"); + + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); + + m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency ); + m_voltageSignal->setVoltage(voltage); +} + + +void ECVoltageSignal::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() ); + deinitPainter(p); +} + diff --git a/src/electronics/components/ecvoltagesignal.h b/src/electronics/components/ecvoltagesignal.h new file mode 100644 index 0000000..7102132 --- /dev/null +++ b/src/electronics/components/ecvoltagesignal.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ECVOLTAGESIGNAL_H +#define ECVOLTAGESIGNAL_H + +#include "component.h" + +/** +@short Provides an alternating voltage source +@author David Saxton +*/ +class ECVoltageSignal : public Component +{ +public: + ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVoltageSignal(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual void drawShape( QPainter &p ); + void dataChanged(); + + VoltageSignal *m_voltageSignal; +}; + +#endif diff --git a/src/electronics/components/ecvoltagesource.cpp b/src/electronics/components/ecvoltagesource.cpp new file mode 100644 index 0000000..4b8c543 --- /dev/null +++ b/src/electronics/components/ecvoltagesource.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "ecvoltagesource.h" + +#include "ecnode.h" +#include "voltagesource.h" +#include "libraryitem.h" +#include "pin.h" + +#include +#include + +const double conductance = 1e5; // Internal resistance + +Item* ECCell::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECCell( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECCell::libraryItem() +{ + QStringList ids; + ids << "ec/battery" << "ec/cell"; + return new LibraryItem( + ids, + i18n("Battery"), + i18n("Sources"), + "cell.png", + LibraryItem::lit_component, + ECCell::construct ); +} + +ECCell::ECCell( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "cell" ) +{ + m_name = i18n("Battery"); + m_desc = i18n("Provides a potential-difference."); + setSize( -8, -8, 16, 16 ); + voltage = 0; + + init1PinLeft(); + init1PinRight(); + + m_pNNode[0]->pin()->setGroundType( Pin::gt_medium ); + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], voltage ); + + createProperty( "voltage", Variant::Type::Double ); + property("voltage")->setUnit("V"); + property("voltage")->setCaption( i18n("Voltage") ); + property("voltage")->setMinValue(-1e12); + property("voltage")->setMaxValue(1e12); + property("voltage")->setValue(5.0); + + addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" ); +} + +ECCell::~ECCell() +{ +} + +void ECCell::dataChanged() +{ + voltage = dataDouble("voltage"); + m_voltageSource->setVoltage(voltage); + + QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V"; + setDisplayText( "voltage", display ); +} + +void ECCell::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-8; + int _y = (int)y()-24; + + p.drawLine( _x, _y+20, _x, _y+28 ); + p.drawLine( _x+5, _y+16, _x+5, _y+32 ); + p.drawLine( _x+10, _y+20, _x+10, _y+28 ); + p.drawLine( _x+15, _y+16, _x+15, _y+32 ); + + deinitPainter(p); +// p.drawPolyline( areaPoints() ); +} + diff --git a/src/electronics/components/ecvoltagesource.h b/src/electronics/components/ecvoltagesource.h new file mode 100644 index 0000000..4ba87ef --- /dev/null +++ b/src/electronics/components/ecvoltagesource.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef ECCELL_H +#define ECCELL_H + +#include "component.h" + +/** +@short Electrical cell +Simple electrical cell that simulates a PD and internal resistance +@author David Saxton +*/ +class ECCell : public Component +{ +public: + ECCell( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECCell(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); + VoltageSource *m_voltageSource; + double voltage; +}; + +#endif diff --git a/src/electronics/components/externalconnection.cpp b/src/electronics/components/externalconnection.cpp new file mode 100644 index 0000000..596727a --- /dev/null +++ b/src/electronics/components/externalconnection.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2004 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 "externalconnection.h" +#include "libraryitem.h" + +#include +#include + +Item* ExternalConnection::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ExternalConnection( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ExternalConnection::libraryItem() +{ + return new LibraryItem( + "ec/external_connection", + i18n("External Connection"), + i18n("Connections"), + "external_connection.png", + LibraryItem::lit_component, + ExternalConnection::construct ); +} + +ExternalConnection::ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "external_connection" ) +{ + m_name = i18n("External Connection"); + m_desc = i18n("Point to connect the circuit to an external entity - e.g. a mechanical component or as part of a subcircuit."); + setSize( -8, -8, 16, 16 ); + + createProperty( "name", Variant::Type::Combo ); + property("name")->setCaption( i18n("Name") ); + property("name")->setValue("ExtCon"); + + init1PinLeft(); + + addDisplayText( "name", QRect( -24, 8, 3*width(), 16 ), "ExtCon" ); +} + +ExternalConnection::~ExternalConnection() +{ +} + + +void ExternalConnection::dataChanged() +{ + QString name = dataString("name"); + + QRect r( -width(), 16, 3*width(), 16 ); + setDisplayText( "name", name ); +} + + +void ExternalConnection::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()-8; + int _y = (int)y()-8; + p.drawEllipse( _x, _y, width(), height() ); + + p.drawLine( _x+3, _y+6, _x+12, _y+6 ); + p.drawLine( _x+8, _y+3, _x+12, _y+6 ); + + p.drawLine( _x+3, _y+9, _x+12, _y+9 ); + p.drawLine( _x+3, _y+9, _x+8, _y+12 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/externalconnection.h b/src/electronics/components/externalconnection.h new file mode 100644 index 0000000..9b733fc --- /dev/null +++ b/src/electronics/components/externalconnection.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2004 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. * + ***************************************************************************/ + +#ifndef EXTERNALCONNECTION_H +#define EXTERNALCONNECTION_H + +#include + +/** +For connecting to something "outside" - e.g. a mechanical component, or as part +of a circuit part +@author David Saxton +*/ +class ExternalConnection : public Component +{ +public: + ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ExternalConnection(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void dataChanged(); + virtual void drawShape( QPainter &p ); +}; + +#endif diff --git a/src/electronics/components/flipflop.cpp b/src/electronics/components/flipflop.cpp new file mode 100644 index 0000000..5c55baf --- /dev/null +++ b/src/electronics/components/flipflop.cpp @@ -0,0 +1,347 @@ +/*************************************************************************** + * 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 "flipflop.h" +#include "icndocument.h" +#include "logic.h" +#include "libraryitem.h" +#include "node.h" +#include "simulator.h" + +#include +#include +#include + + +//BEGIN class ECDFlipFlop +Item* ECDFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDFlipFlop::libraryItem() +{ + return new LibraryItem( + "ec/d_flipflop", + i18n("D Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECDFlipFlop::construct ); +} + +ECDFlipFlop::ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "d_flipflop" ) +{ + m_name = i18n("D-Type Flip-Flop"); + m_desc = i18n("The output state is set from the input state when the clock is pulsed."); + + setSize( -32, -24, 64, 48 ); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_prevD[0] = m_prevD[1] = false; + m_whichPrevD = 0; + m_prevDSimTime = 0; + m_pSimulator = Simulator::self(); + + m_bPrevClock = false; + m_pD = createLogicIn( m_pNNode[0] ); + m_pClock = createLogicIn( m_pNNode[1] ); + m_pQ = createLogicOut( m_pPNode[0], false ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + setp = createLogicIn( createPin( 0, -32, 90, "set" ) ); + rstp = createLogicIn( createPin( 0, 32, 270, "rst" ) ); + + addDisplayText( "D", QRect( -32, -16, 20, 16 ), "D" ); + addDisplayText( ">", QRect( -32, 0, 20, 16 ), ">" ); + addDisplayText( "Q", QRect( 12, -16, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 12, 0, 20, 16 ), "Q'" ); + addDisplayText( "Set", QRect( -16, -20, 32, 16 ), "Set" ); + addDisplayText( "Rst", QRect( -16, 4, 32, 16 ), "Rst" ); + + m_pD->setCallback( this, (CallbackPtr)(&ECDFlipFlop::inputChanged) ); + m_pClock->setCallback( this, (CallbackPtr)(&ECDFlipFlop::clockChanged) ); + setp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) ); + rstp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) ); + + inStateChanged(false); +} + +ECDFlipFlop::~ECDFlipFlop() +{ +} + +void ECDFlipFlop::asyncChanged(bool) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + if(set || rst) + { + m_pQ->setHigh(set); + m_pQBar->setHigh(rst); + } +} + +void ECDFlipFlop::inputChanged( bool newState ) +{ + unsigned long long simTime = m_pSimulator->time(); + if ( (simTime == m_prevDSimTime) && (newState == m_prevD[m_whichPrevD]) ) + return; + + m_prevDSimTime = simTime; + m_whichPrevD = 1-m_whichPrevD; + m_prevD[m_whichPrevD] = newState; +} + +void ECDFlipFlop::clockChanged( bool newState ) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + bool fallingEdge = m_bPrevClock && !newState; + m_bPrevClock = newState; + + if( set || rst ) return; + + if (fallingEdge) + { + unsigned long long simTime = m_pSimulator->time(); + bool d = ( simTime == m_prevDSimTime ) ? m_prevD[1-m_whichPrevD] : m_prevD[m_whichPrevD]; + + m_pQ->setHigh(d); + m_pQBar->setHigh(!d); + } +} + +void ECDFlipFlop::inStateChanged(bool) +{ + // Only called when the flipflop is created. + m_pQ->setHigh(false); + m_pQBar->setHigh(true); +} +//END class ECDFlipFlop + + +//BEGIN class ECJKFlipFlop +Item* ECJKFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECJKFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECJKFlipFlop::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/jk_flipflop"), + i18n("JK Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECJKFlipFlop::construct ); +} + +ECJKFlipFlop::ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "jk_flipflop" ) +{ + m_name = i18n("JK-Type Flip-Flop"); + m_desc = i18n("The output state is set according to J and K when the clock is pulsed."); + + setSize( -32, -32, 64, 64 ); + + init3PinLeft( -16, 0, 16 ); + init2PinRight( -16, 16 ); + + m_pJ = createLogicIn( m_pNNode[0] ); + m_pClock = createLogicIn( m_pNNode[1] ); + m_pK = createLogicIn( m_pNNode[2] ); + + m_pQ = createLogicOut( m_pPNode[0], false ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + setp = createLogicIn( createPin( 0, -40, 90, "set" ) ); + rstp = createLogicIn( createPin( 0, 40, 270, "rst" ) ); + + addDisplayText( "J", QRect( -32, -24, 20, 16 ), "J" ); + addDisplayText( ">", QRect( -32, -8, 20, 16 ), ">" ); + addDisplayText( "K", QRect( -32, 8, 20, 16 ), "K" ); + addDisplayText( "Q", QRect( 12, -24, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 12, 8, 20, 16 ), "Q'" ); + addDisplayText( "Set", QRect( -16, -28, 32, 16 ), "Set" ); + addDisplayText( "Rst", QRect( -16, 12, 32, 16 ), "Rst" ); + + m_pClock->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::clockChanged) ); + setp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) ); + rstp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) ); + + inStateChanged(false); +} + +ECJKFlipFlop::~ECJKFlipFlop() +{ +} + +void ECJKFlipFlop::clockChanged(bool newvalue) +{ + bool j = m_pJ->isHigh(); + bool k = m_pK->isHigh(); + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + if( set || rst ) return; + +// a JK flip-flop change state when clock do 1->0 + if (!newvalue && (j || k)) { + if ( j && k ) { + m_pQ->setHigh(!prev_state); + m_pQBar->setHigh(prev_state); + prev_state = !prev_state; + } else { + // (J=1 && K=0) || (J=0 && K=1) + m_pQ->setHigh(j); + m_pQBar->setHigh(k); + prev_state = j; + } + } +} + +void ECJKFlipFlop::asyncChanged(bool) +{ + bool set = setp->isHigh(); + bool rst = rstp->isHigh(); + + if (set || rst) { + m_pQ->setHigh(set); + m_pQBar->setHigh(rst); + prev_state = set; + } +} + +void ECJKFlipFlop::inStateChanged(bool) +{ + m_pQBar->setHigh(true); + m_pQ->setHigh(false); + prev_state = false; +} +//END class ECJKFlipFlop + + +//BEGIN class ECSRFlipFlop +Item* ECSRFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSRFlipFlop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSRFlipFlop::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/sr_flipflop"), + i18n("SR Flip-Flop"), + i18n("Integrated Circuits"), + "ic3.png", + LibraryItem::lit_component, + ECSRFlipFlop::construct ); +} + +ECSRFlipFlop::ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "sr_flipflop" ) +{ + m_name = i18n("SR Flip-Flop"); + m_desc = i18n("The output is made high by holding set high, and low by holding reset high."); + + setSize( -24, -24, 48, 48 ); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_pS = createLogicIn( m_pNNode[0] ); + m_pR = createLogicIn( m_pNNode[1] ); + m_pQ = createLogicOut( m_pPNode[0], true ); + m_pQBar = createLogicOut( m_pPNode[1], false ); + + old_q1 = true; + old_q2 = false; + m_pQ->setHigh(old_q1); + m_pQBar->setHigh(old_q2); + + addDisplayText( "S", QRect( -24, -16, 20, 16 ), "S" ); + addDisplayText( "R", QRect( -24, 0, 20, 16 ), "R" ); + addDisplayText( "Q", QRect( 4, -16, 20, 16 ), "Q" ); + addDisplayText( "Q'", QRect( 4, 0, 20, 16 ), "Q'" ); + + m_pS->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pR->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pQ->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); + m_pQBar->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) ); +} + +ECSRFlipFlop::~ECSRFlipFlop() +{ +} + +void ECSRFlipFlop::inStateChanged(bool) +{ + // Q = v_q1, Q-bar = v_q2 + bool new_q1 = false; + bool new_q2 = false; + + bool s = m_pS->isHigh(); + bool r = m_pR->isHigh(); + bool q1 = m_pQ->isHigh(); + bool q2 = m_pQBar->isHigh(); + + // Easy ones to do :-) + if (!q1) new_q2 = true; + if (!q2) new_q1 = true; + + if ( q1 && q2 ) + { + if ( s && !r ) + { + new_q1 = true; + new_q2 = false; + } + else if ( !s && r ) + { + new_q1 = false; + new_q2 = true; + } + else if ( s && r ) + { + new_q1 = old_q1; + new_q2 = old_q2; + } + else if ( !s && !r ) + { + new_q1 = false; + new_q2 = false; + } + } + else if ( q1 && !q2 ) + { + // Note: We only need to set the value of v_q2 + if ( r && !s ) new_q2 = true; + else new_q2 = false; + } + else if ( !q1 && q2 ) + { + // Note: We only need to set the value of v_q1 + if ( s && !r ) new_q1 = true; + else new_q1 = false; + } + + old_q1 = new_q1; + old_q2 = new_q2; + + m_pQ->setHigh(new_q1); + m_pQBar->setHigh(new_q2); +} +//END class ECSRFlipFlop diff --git a/src/electronics/components/flipflop.h b/src/electronics/components/flipflop.h new file mode 100644 index 0000000..7b9d5b7 --- /dev/null +++ b/src/electronics/components/flipflop.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FLIPFLOP_H +#define FLIPFLOP_H + +#include "component.h" +#include "logic.h" + +class Simulator; + +/** +@short Boolean D-Type Flip-Flop +@author David Saxton +*/ +class ECDFlipFlop : public CallbackClass, public Component +{ +public: + ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inputChanged( bool newState ); + void inStateChanged( bool newState ); + void asyncChanged(bool newState ); + void clockChanged(bool newState ); + + LogicIn *m_pD; + LogicIn *m_pClock; + LogicOut *m_pQ; + LogicOut *m_pQBar; + LogicIn *setp; + LogicIn *rstp; + bool m_bPrevClock; + + bool m_prevD[2]; + unsigned m_whichPrevD:1; + unsigned long long m_prevDSimTime; + Simulator * m_pSimulator; +}; + + +/** +@short Boolean JK-Type Flip-Flop +@author Couriousous +*/ +class ECJKFlipFlop : public CallbackClass, public Component +{ +public: + ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECJKFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + void asyncChanged(bool newState ); + void clockChanged(bool newState ); + bool prev_state; + LogicIn *m_pJ; + LogicIn *m_pClock; + LogicIn *m_pK; + LogicIn *setp; + LogicIn *rstp; + LogicOut *m_pQ; + LogicOut *m_pQBar; +}; + + +/** +@short Boolean Set-Reset Flip-Flop +@author David Saxton +*/ +class ECSRFlipFlop : public CallbackClass, public Component +{ +public: + ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSRFlipFlop(); + virtual bool canFlip() const { return true; } + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + LogicIn * m_pS; + LogicIn * m_pR; + LogicOut * m_pQ; + LogicOut * m_pQBar; + bool old_q1; + bool old_q2; +}; + +#endif diff --git a/src/electronics/components/fulladder.cpp b/src/electronics/components/fulladder.cpp new file mode 100644 index 0000000..ad5e40c --- /dev/null +++ b/src/electronics/components/fulladder.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2004 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 "fulladder.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + + +Item* FullAdder::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new FullAdder( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* FullAdder::libraryItem() +{ + return new LibraryItem( + QString("ec/adder"), + i18n("Adder"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + FullAdder::construct + ); +} + +FullAdder::FullAdder( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "adder" ) +{ + m_name = i18n("Adder"); +// m_desc = i18n("Insert missing adder help here."); + + ALogic = BLogic = inLogic = 0l; + outLogic = SLogic = 0l; + + QStringList pins = QStringList::split( ',', "A,B,>,,S,C", true ); + initDIPSymbol( pins, 48 ); + initDIP(pins); + + ECNode *node; + + node = ecNodeWithID("S"); + SLogic = createLogicOut( node, false ); + + node = ecNodeWithID("C"); + outLogic = createLogicOut( node, false ); + + node = ecNodeWithID("A"); + ALogic = createLogicIn(node); + + node = ecNodeWithID("B"); + BLogic = createLogicIn(node); + + node = ecNodeWithID(">"); + inLogic = createLogicIn(node); + + + ALogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); + BLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); + inLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) ); +} + +FullAdder::~FullAdder() +{ +} + + +void FullAdder::inStateChanged( bool /*state*/ ) +{ + const bool A = ALogic->isHigh(); + const bool B = BLogic->isHigh(); + const bool in = inLogic->isHigh(); + + const bool out = (!A && B && in) || (A && !B && in) || (A && B); + const bool S = (!A && !B && in) || (!A && B && !in) || (A && !B && !in) || (A && B && in); + + SLogic->setHigh(S); + outLogic->setHigh(out); +} + + diff --git a/src/electronics/components/fulladder.h b/src/electronics/components/fulladder.h new file mode 100644 index 0000000..d4277e5 --- /dev/null +++ b/src/electronics/components/fulladder.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2004 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. * + ***************************************************************************/ + +#ifndef ECFullAdder_H +#define ECFullAdder_H + +#include "component.h" +#include "logic.h" + +/** +@author David Saxton +*/ +class FullAdder : public CallbackClass, public Component +{ +public: + FullAdder( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FullAdder(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + virtual bool canFlip() const { return true; } + +protected: + void inStateChanged( bool newState ); + + LogicIn *ALogic, *BLogic, *inLogic; + LogicOut *outLogic, *SLogic; +}; + +#endif diff --git a/src/electronics/components/inductor.cpp b/src/electronics/components/inductor.cpp new file mode 100644 index 0000000..9e30b34 --- /dev/null +++ b/src/electronics/components/inductor.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * 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 "inductance.h" +#include "inductor.h" +#include "libraryitem.h" + +#include +#include + +Item* Inductor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Inductor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Inductor::libraryItem() +{ + return new LibraryItem( + "ec/inductor", + i18n("Inductor"), + i18n("Discrete"), + "inductor.png", + LibraryItem::lit_component, + Inductor::construct + ); +} + +Inductor::Inductor( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "inductor" ) +{ + m_name = i18n("Inductor"); +// m_desc = i18n("Stores electrical charge.

" +// "The voltage across the inductor and inductance are related by Charge = Inductance x Voltage."); + setSize( -16, -8, 32, 16 ); + + init1PinLeft(); + init1PinRight(); + + m_pInductance = createInductance( m_pNNode[0], m_pPNode[0], 0.001 ); + + createProperty( "Inductance", Variant::Type::Double ); + property("Inductance")->setCaption( i18n("Inductance") ); + property("Inductance")->setUnit("H"); + property("Inductance")->setMinValue(1e-12); + property("Inductance")->setMaxValue(1e12); + property("Inductance")->setValue(1e-3); + + addDisplayText( "inductance", QRect( -8, -24, 16, 16 ), "", false ); +} + +Inductor::~Inductor() +{ +} + +void Inductor::dataChanged() +{ + double inductance = dataDouble("Inductance"); + + QString display = QString::number( inductance / getMultiplier(inductance), 'g', 3 ) + getNumberMag(inductance) + "H"; + setDisplayText( "inductance", display ); + + m_pInductance->setInductance(inductance); +} + +void Inductor::drawShape( QPainter &p ) +{ + initPainter(p); + int _y = int(y()); + int _x = int(x()); + + p.drawArc( _x-16, _y-5, 11, 11, 0, 180*16 ); + p.drawArc( _x-5, _y-5, 11, 11, 0, 180*16 ); + p.drawArc( _x+6, _y-5, 11, 11, 0, 180*16 ); + + deinitPainter(p); +} + diff --git a/src/electronics/components/inductor.h b/src/electronics/components/inductor.h new file mode 100644 index 0000000..abb4eec --- /dev/null +++ b/src/electronics/components/inductor.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef INDUCTOR_H +#define INDUCTOR_H + +#include + +/** +@author David Saxton +*/ +class Inductor : public Component +{ + public: + Inductor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Inductor(); + + static Item * construct( ItemDocument * itemDocument, bool newItem, const char * id ); + static LibraryItem * libraryItem(); + + private: + void dataChanged(); + virtual void drawShape( QPainter & p ); + + Inductance * m_pInductance; +}; + +#endif diff --git a/src/electronics/components/magnitudecomparator.cpp b/src/electronics/components/magnitudecomparator.cpp new file mode 100644 index 0000000..2659122 --- /dev/null +++ b/src/electronics/components/magnitudecomparator.cpp @@ -0,0 +1,206 @@ +/*************************************************************************** + * Copyright (C) 2005 by Fredy Yanardi * + * * + * 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 "libraryitem.h" +#include "logic.h" +#include "magnitudecomparator.h" +#include "variant.h" + +#include +#include + +Item* MagnitudeComparator::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MagnitudeComparator( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* MagnitudeComparator::libraryItem() +{ + return new LibraryItem( + QString("ec/magnitudecomparator"), + i18n("Magnitude Comparator"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + MagnitudeComparator::construct + ); +} + +MagnitudeComparator::MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "magnitudecomparator" ) +{ + m_name = i18n("Magnitude Comparator"); +// m_desc = i18n("Compares to two binary number and generates input to indicate which binary number has greater magnitude. It has 3 cascading inputs: I0 for IA > B, I1 for IA < B, and I2 for IA = B and 3 outputs: O0 for OA > B, O1 for OA < B, and O2 for OA = B"); + m_desc = i18n("Compares two binary numbers and generates output to indicate which binary number has the greater magnitude. It has 3 cascading inputs:" + "
  • I: A > B
  • " + "
  • I: A < B
  • " + "
  • I: A = B
" + "and 3 outputs:" + "
  • O: A > B
  • " + "
  • O: A < B
  • " + "
  • O: A = B
"); + + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setCaption( i18n("Number Inputs") ); + property("numInput")->setMinValue(1); + property("numInput")->setMaxValue(8); + property("numInput")->setValue(4); + + m_oldABLogicCount = 0; + cascadingInputs = 3; + outputs = 3; + + firstTime = true; +} + +MagnitudeComparator::~MagnitudeComparator() +{ +} + + +void MagnitudeComparator::dataChanged() +{ + initPins(); +} + + +void MagnitudeComparator::inStateChanged() +{ + int i; + + for ( i = 0; i < 3; i++ ) + m_output[i]->setHigh(false); + +// for ( i = dataInt("numInput")-1; i >= 0; i-- ) { + for ( i = m_oldABLogicCount-1; i >= 0; i-- ) { + if (m_aLogic[i]->isHigh() && !m_bLogic[i]->isHigh()) + { + m_output[0]->setHigh(true); + return; + } + else if ( !m_aLogic[i]->isHigh() && m_bLogic[i]->isHigh() ) { + m_output[1]->setHigh(true); + return; + } + } + + if ( m_cLogic[2]->isHigh() ) + m_output[2]->setHigh(true); + else if ( m_cLogic[0]->isHigh() ) + if ( !m_cLogic[1]->isHigh() ) + m_output[0]->setHigh(true); + else + ; + else if ( m_cLogic[1]->isHigh() ) + m_output[1]->setHigh(true); + else { + m_output[0]->setHigh(true); + m_output[1]->setHigh(true); + } +} + + +void MagnitudeComparator::initPins() +{ + const double numInputs = dataInt("numInput"); + int newABLogicCount = (int)numInputs; + + if ( newABLogicCount == m_oldABLogicCount ) + return; + + QStringList leftPins; + int space = 3 - newABLogicCount; + for ( int i = 0; i < space; i++ ) + leftPins << ""; + for ( int i = 0; i < newABLogicCount; i++ ) + leftPins << QString("A%1").arg( QString::number(i) ); + for ( int i = 0; i < newABLogicCount; i++ ) + leftPins << QString("B%1").arg( QString::number(i) ); + for ( int i = 0; i < space; i++ ) + leftPins << ""; + + QStringList rightPins; + space = -space; + for ( int i = 0; i < space; i++ ) + rightPins << ""; + QString inNames[] = { "I: A>B", "I: AB", "O: AsetCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged)); + } + + m_output.resize(3); + for ( int i = 0; i < outputs; i++ ) + { + node = ecNodeWithID( outNames[i] ); + m_output.insert( i, createLogicOut(node,false) ); + } + firstTime = false; + } + + if ( newABLogicCount > m_oldABLogicCount ) + { + m_aLogic.resize(newABLogicCount); + for ( int i=m_oldABLogicCount; isetCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) ); + } + + m_bLogic.resize(newABLogicCount); + for ( int i=m_oldABLogicCount; isetCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) ); + } + } + else + { + for ( int i=newABLogicCount; i +#include + +/** +@author Fredy Yanardi + */ +class MagnitudeComparator : public CallbackClass, public Component +{ + public: + MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MagnitudeComparator(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + protected: + void initPins(); + virtual void dataChanged(); + void inStateChanged(); + + int m_oldABLogicCount; + int cascadingInputs; + int outputs; + bool firstTime; + + QBitArray m_data; + + QPtrVector m_aLogic; + QPtrVector m_bLogic; + QPtrVector m_cLogic; + QPtrVector m_output; +}; + +#endif diff --git a/src/electronics/components/matrixdisplay.cpp b/src/electronics/components/matrixdisplay.cpp new file mode 100644 index 0000000..dd40b6a --- /dev/null +++ b/src/electronics/components/matrixdisplay.cpp @@ -0,0 +1,291 @@ +/*************************************************************************** + * 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 "colorcombo.h" +#include "diode.h" +#include "ecled.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "matrixdisplay.h" +#include "simulator.h" + +#include +#include +#include +#include + +Item* MatrixDisplay::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MatrixDisplay( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* MatrixDisplay::libraryItem() +{ + return new LibraryItem( + "ec/matrix_display", + i18n("Matrix Display"), + i18n("Outputs"), + "matrixdisplay.png", + LibraryItem::lit_component, + MatrixDisplay::construct ); +} + + +MatrixDisplay::MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "matrix_display" ) +{ + m_name = i18n("Matrix Display"); + m_desc = i18n("A matrix display of LEDs with a configurable number of columns and rows."); + m_bDynamicContent = true; + + //BEGIN Reset members + for ( unsigned i = 0; i < max_md_height; i++ ) + m_pRowNodes[i] = 0l; + for ( unsigned i = 0; i < max_md_width; i++ ) + m_pColNodes[i] = 0l; + + m_lastUpdatePeriod = 0.0; + m_r = m_g = m_b = 0.0; + m_bRowCathode = true; + m_numRows = 0; + m_numCols = 0; + //END Reset members + + createProperty( "0-rows", Variant::Type::Int ); + property("0-rows")->setCaption( i18n("Rows") ); + property("0-rows")->setMinValue(1); + property("0-rows")->setMaxValue(max_md_height); + property("0-rows")->setValue(7); + + createProperty( "1-cols", Variant::Type::Int ); + property("1-cols")->setCaption( i18n("Columns") ); + property("1-cols")->setMinValue(1); + property("1-cols")->setMaxValue(max_md_width); + property("1-cols")->setValue(5); + + createProperty( "color", Variant::Type::Color ); + property("color")->setCaption( i18n("Color") ); + property("color")->setColorScheme( ColorCombo::LED ); + + createProperty( "diode-configuration", Variant::Type::Select ); + property("diode-configuration")->setCaption( i18n("Configuration") ); + property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") ); + property("diode-configuration")->setValue("Row Cathode"); + property("diode-configuration")->setAdvanced(true); +} + + +MatrixDisplay::~MatrixDisplay() +{ +} + + +void MatrixDisplay::dataChanged() +{ + QColor color = dataColor("color"); + m_r = double(color.red()) / double(0x100); + m_g = double(color.green()) / double(0x100); + m_b = double(color.blue()) / double(0x100); + + int numRows = dataInt("0-rows"); + int numCols = dataInt("1-cols"); + + bool ledsChanged = (numRows != int(m_numRows)) || (numCols != int(m_numCols)); + + if (ledsChanged) + initPins( numRows, numCols ); + + bool rowCathode = dataString("diode-configuration") == "Row Cathode"; + if ( (rowCathode != m_bRowCathode) || ledsChanged) + { + m_bRowCathode = rowCathode; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + { + removeElement( m_pDiodes[i][j], false ); + if (rowCathode) + m_pDiodes[i][j] = createDiode( m_pColNodes[i], m_pRowNodes[j] ); + else + m_pDiodes[i][j] = createDiode( m_pRowNodes[j], m_pColNodes[i] ); + } + } + } +} + + +void MatrixDisplay::initPins( unsigned numRows, unsigned numCols ) +{ + if ( (numRows == m_numRows) && (numCols == m_numCols) ) + return; + + if ( numRows > max_md_height ) + numRows = max_md_height; + + if ( numCols > max_md_width ) + numCols = max_md_width; + + m_lastUpdatePeriod = 0.0; + + //BEGIN Remove diodes + // All the diodes are going to be readded from dataChanged (where this + // function is called from), so easiest just to delete the diodes now and + // resize. + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + removeElement( m_pDiodes[i][j], false ); + } + + m_avgBrightness.resize(numCols); + m_lastBrightness.resize(numCols); + m_pDiodes.resize(numCols); + + for ( unsigned i = 0; i < numCols; i++ ) + { + m_avgBrightness[i].resize(numRows); + m_lastBrightness[i].resize(numRows); + m_pDiodes[i].resize(numRows); + + for ( unsigned j = 0; j < numRows; j++ ) + { + m_avgBrightness[i][j] = 0.0; + m_lastBrightness[i][j] = 255; + m_pDiodes[i][j] = 0l; + } + + } + //END Remove diodes + + + //BEGIN Create or destroy pins + if ( numCols >= m_numCols ) + { + for ( unsigned i = m_numCols; i < numCols; i++ ) + m_pColNodes[i] = createPin( 0, 0, 270, colPinID(i) ); + } + else + { + for ( unsigned i = numCols; i < m_numCols; i++ ) + { + removeNode( colPinID(i) ); + m_pColNodes[i] = 0l; + } + } + m_numCols = numCols; + + if ( numRows >= m_numRows ) + { + for ( unsigned i = m_numRows; i < numRows; i++ ) + m_pRowNodes[i] = createPin( 0, 0, 0, rowPinID(i) ); + } + else + { + for ( unsigned i = numRows; i < m_numRows; i++ ) + { + removeNode( rowPinID(i) ); + m_pRowNodes[i] = 0l; + } + } + m_numRows = numRows; + //END Create or destroy pins + + + //BEGIN Position pins et al + setSize( -int(numCols+1)*8, -int(numRows+1)*8, int(numCols+1)*16, int(numRows+1)*16, true ); + + for ( int i = 0; i < int(m_numCols); i++ ) + { + m_nodeMap[colPinID(i)].x = offsetX() + 16 + 16*i; + m_nodeMap[colPinID(i)].y = offsetY() + height() + 8; + } + + for ( int i = 0; i < int(m_numRows); i++ ) + { + m_nodeMap[rowPinID(i)].x = offsetX() - 8; + m_nodeMap[rowPinID(i)].y = offsetY() + 16 + 16*i; + } + + updateAttachedPositioning(); + //END Position pins et al +} + + +QString MatrixDisplay::colPinID( int col ) const +{ + return QString("col_%1").arg(QString::number(col)); +} +QString MatrixDisplay::rowPinID( int row ) const +{ + return QString("row_%1").arg(QString::number(row)); +} + + +void MatrixDisplay::stepNonLogic() +{ + double interval = 1./LINEAR_UPDATE_RATE; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + m_avgBrightness[i][j] += ECLed::brightness( m_pDiodes[i][j]->current() )*interval; + } + + m_lastUpdatePeriod += interval; +} + + +void MatrixDisplay::drawShape( QPainter &p ) +{ + if ( isSelected() ) + p.setPen(m_selectedCol); + p.drawRect( boundingRect() ); + + initPainter(p); + + const int _x = int(x()+offsetX()); + const int _y = int(y()+offsetY()); + + // To avoid flicker, require at least a 10 ms sample before changing + // the brightness + double minUpdatePeriod = 0.0099; + + for ( int i = 0; i < int(m_numCols); i++ ) + { + for ( int j = 0; j < int(m_numRows); j++ ) + { + if ( m_lastUpdatePeriod > minUpdatePeriod ) + m_lastBrightness[i][j] = unsigned(m_avgBrightness[i][j]/m_lastUpdatePeriod); + + double _b = m_lastBrightness[i][j]; + + QColor brush = QColor( uint(255-(255-_b)*(1-m_r)), uint(255-(255-_b)*(1-m_g)), uint(255-(255-_b)*(1-m_b)) ); + p.setBrush(brush); + p.setPen( Qt::NoPen ); + p.drawEllipse( _x+10+i*16, _y+10+j*16, 12, 12 ); + } + } + + if ( m_lastUpdatePeriod > minUpdatePeriod ) + { + m_lastUpdatePeriod = 0.0; + + for ( unsigned i = 0; i < m_numCols; i++ ) + { + for ( unsigned j = 0; j < m_numRows; j++ ) + m_avgBrightness[i][j] = 0.0; + } + } + + deinitPainter(p); +} diff --git a/src/electronics/components/matrixdisplay.h b/src/electronics/components/matrixdisplay.h new file mode 100644 index 0000000..4851817 --- /dev/null +++ b/src/electronics/components/matrixdisplay.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef MATRIXDISPLAY_H +#define MATRIXDISPLAY_H + +#include +#include + +const unsigned max_md_width = 100; +const unsigned max_md_height = 20; + +/** +@author David Saxton +*/ +class MatrixDisplay : public Component +{ + public: + MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MatrixDisplay(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + virtual void drawShape( QPainter &p ); + virtual void dataChanged(); + void initPins( unsigned numRows, unsigned numCols ); + QString colPinID( int col ) const; + QString rowPinID( int row ) const; + + + QValueVector< QValueVector > m_avgBrightness; + QValueVector< QValueVector > m_lastBrightness; + QValueVector< QValueVector > m_pDiodes; + + ECNode * m_pRowNodes[max_md_height]; + ECNode * m_pColNodes[max_md_width]; + + double m_lastUpdatePeriod; + + double m_r, m_g, m_b; + bool m_bRowCathode; + + unsigned m_numRows; + unsigned m_numCols; +}; + +#endif diff --git a/src/electronics/components/matrixdisplaydriver.cpp b/src/electronics/components/matrixdisplaydriver.cpp new file mode 100644 index 0000000..da00bb7 --- /dev/null +++ b/src/electronics/components/matrixdisplaydriver.cpp @@ -0,0 +1,380 @@ +/*************************************************************************** + * 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 "libraryitem.h" +#include "logic.h" +#include "matrixdisplaydriver.h" + +#include +#include +#include + +#include + +// Thank you Scott Dattalo! +// http://www.dattalo.com/gnupic/lcdfont.inc + +static char characterMap[256][5] = { +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //0 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //1 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //2 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //3 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //4 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //5 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //6 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //7 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //8 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //9 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //10 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //11 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //12 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //13 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //14 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //15 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //16 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //17 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //18 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //19 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //20 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //21 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //22 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //23 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //24 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //25 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //26 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //27 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //28 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //29 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //30 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //31 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //32 +{ 0x00, 0x00, 0x7d, 0x00, 0x00 }, //33 +{ 0x00, 0x70, 0x00, 0x70, 0x00 }, //34 +{ 0x14, 0x7f, 0x14, 0x7f, 0x14 }, //35 +{ 0x12, 0x2a, 0x7f, 0x2a, 0x24 }, //36 +{ 0x62, 0x64, 0x08, 0x13, 0x23 }, //37 +{ 0x36, 0x49, 0x55, 0x22, 0x05 }, //38 +{ 0x00, 0x50, 0x60, 0x00, 0x00 }, //39 +{ 0x00, 0x1c, 0x22, 0x41, 0x00 }, //40 +{ 0x00, 0x41, 0x22, 0x1c, 0x00 }, //41 +{ 0x14, 0x08, 0x3e, 0x08, 0x14 }, //42 +{ 0x08, 0x08, 0x3e, 0x08, 0x08 }, //43 +{ 0x00, 0x05, 0x06, 0x00, 0x00 }, //44 +{ 0x08, 0x08, 0x08, 0x08, 0x08 }, //45 +{ 0x00, 0x03, 0x03, 0x00, 0x00 }, //46 +{ 0x02, 0x04, 0x08, 0x10, 0x20 }, //47 +{ 0x3e, 0x45, 0x49, 0x51, 0x3e }, //48 +{ 0x00, 0x21, 0x7f, 0x01, 0x00 }, //49 +{ 0x21, 0x43, 0x45, 0x49, 0x31 }, //50 +{ 0x42, 0x41, 0x51, 0x69, 0x46 }, //51 +{ 0x0c, 0x14, 0x24, 0x7f, 0x04 }, //52 +{ 0x72, 0x51, 0x51, 0x51, 0x4e }, //53 +{ 0x1e, 0x29, 0x49, 0x49, 0x06 }, //54 +{ 0x40, 0x47, 0x48, 0x50, 0x60 }, //55 +{ 0x36, 0x49, 0x49, 0x49, 0x36 }, //56 +{ 0x30, 0x49, 0x49, 0x4a, 0x3c }, //57 +{ 0x00, 0x36, 0x36, 0x00, 0x00 }, //58 +{ 0x00, 0x35, 0x36, 0x00, 0x00 }, //59 +{ 0x08, 0x14, 0x22, 0x41, 0x00 }, //60 +{ 0x14, 0x14, 0x14, 0x14, 0x14 }, //61 +{ 0x41, 0x22, 0x14, 0x08, 0x00 }, //62 +{ 0x20, 0x40, 0x45, 0x48, 0x30 }, //63 +{ 0x26, 0x49, 0x4f, 0x41, 0x3e }, //64 +{ 0x3f, 0x44, 0x44, 0x44, 0x3f }, //65 +{ 0x7f, 0x49, 0x49, 0x49, 0x36 }, //66 +{ 0x3e, 0x41, 0x41, 0x41, 0x22 }, //67 +{ 0x7f, 0x41, 0x41, 0x41, 0x3e }, //68 +{ 0x7f, 0x49, 0x49, 0x49, 0x41 }, //69 +{ 0x7f, 0x48, 0x48, 0x48, 0x40 }, //70 +{ 0x3e, 0x41, 0x49, 0x49, 0x2f }, //71 +{ 0x7f, 0x08, 0x08, 0x08, 0x7f }, //72 +{ 0x00, 0x41, 0x7f, 0x41, 0x00 }, //73 +{ 0x02, 0x01, 0x41, 0x7e, 0x40 }, //74 +{ 0x7f, 0x08, 0x14, 0x22, 0x41 }, //75 +{ 0x7f, 0x01, 0x01, 0x01, 0x01 }, //76 +{ 0x7f, 0x40, 0x20, 0x40, 0x7f }, //77 +{ 0x7f, 0x10, 0x08, 0x04, 0x7f }, //78 +{ 0x3e, 0x41, 0x41, 0x41, 0x3e }, //79 +{ 0x7f, 0x48, 0x48, 0x48, 0x30 }, //80 +{ 0x3e, 0x41, 0x45, 0x42, 0x3d }, //81 +{ 0x7f, 0x48, 0x4c, 0x4a, 0x31 }, //82 +{ 0x31, 0x49, 0x49, 0x49, 0x46 }, //83 +{ 0x40, 0x40, 0x7f, 0x40, 0x40 }, //84 +{ 0x7e, 0x01, 0x01, 0x01, 0x7e }, //85 +{ 0x7c, 0x02, 0x01, 0x02, 0x7c }, //86 +{ 0x7e, 0x01, 0x0e, 0x01, 0x7e }, //87 +{ 0x63, 0x14, 0x08, 0x14, 0x63 }, //88 +{ 0x70, 0x08, 0x07, 0x08, 0x70 }, //89 +{ 0x43, 0x45, 0x49, 0x51, 0x61 }, //90 +{ 0x00, 0x7f, 0x41, 0x41, 0x00 }, //91 +{ 0x54, 0x34, 0x1f, 0x34, 0x54 }, //92 +{ 0x00, 0x41, 0x41, 0x7f, 0x00 }, //93 +{ 0x10, 0x20, 0x40, 0x20, 0x10 }, //94 +{ 0x01, 0x01, 0x01, 0x01, 0x01 }, //95 +{ 0x00, 0x40, 0x20, 0x10, 0x00 }, //96 +{ 0x02, 0x15, 0x15, 0x15, 0x0f }, //97 +{ 0x7f, 0x09, 0x11, 0x11, 0x0e }, //98 +{ 0x0e, 0x11, 0x11, 0x11, 0x02 }, //99 +{ 0x0e, 0x11, 0x11, 0x09, 0x7f }, //100 +{ 0x0e, 0x15, 0x15, 0x15, 0x0c }, //101 +{ 0x08, 0x3f, 0x48, 0x40, 0x20 }, //102 +{ 0x30, 0x49, 0x49, 0x49, 0x7e }, //103 +{ 0x7f, 0x08, 0x10, 0x10, 0x0f }, //104 +{ 0x00, 0x11, 0x5f, 0x01, 0x00 }, //105 +{ 0x02, 0x01, 0x21, 0x7e, 0x00 }, //106 +{ 0x7f, 0x04, 0x0a, 0x11, 0x00 }, //107 +{ 0x00, 0x41, 0x7f, 0x01, 0x00 }, //108 +{ 0x1f, 0x10, 0x0c, 0x10, 0x0f }, //109 +{ 0x1f, 0x08, 0x10, 0x10, 0x0f }, //110 +{ 0x0e, 0x11, 0x11, 0x11, 0x0e }, //111 +{ 0x1f, 0x14, 0x14, 0x14, 0x08 }, //112 +{ 0x08, 0x14, 0x14, 0x0c, 0x1f }, //113 +{ 0x1f, 0x08, 0x10, 0x10, 0x08 }, //114 +{ 0x09, 0x15, 0x15, 0x15, 0x12 }, //115 +{ 0x20, 0x7e, 0x21, 0x01, 0x02 }, //116 +{ 0x1e, 0x01, 0x01, 0x02, 0x1f }, //117 +{ 0x1c, 0x02, 0x01, 0x02, 0x1c }, //118 +{ 0x1e, 0x01, 0x06, 0x01, 0x1e }, //119 +{ 0x11, 0x0a, 0x04, 0x0a, 0x11 }, //120 +{ 0x18, 0x05, 0x05, 0x05, 0x1e }, //121 +{ 0x11, 0x13, 0x15, 0x19, 0x11 }, //122 +{ 0x00, 0x08, 0x36, 0x41, 0x00 }, //123 +{ 0x00, 0x00, 0x7f, 0x00, 0x00 }, //124 +{ 0x00, 0x41, 0x36, 0x08, 0x00 }, //125 +{ 0x08, 0x08, 0x2a, 0x1c, 0x08 }, //126 +{ 0x08, 0x1c, 0x2a, 0x08, 0x08 }, //127 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //128 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //129 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //130 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //131 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //132 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //133 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //134 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //135 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //136 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //137 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //138 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //139 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //140 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //141 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //142 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //143 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //144 +{ 0x07, 0x05, 0x07, 0x00, 0x00 }, //145 +{ 0x00, 0x00, 0x78, 0x40, 0x40 }, //146 +{ 0x01, 0x01, 0x0f, 0x00, 0x00 }, //147 +{ 0x04, 0x02, 0x01, 0x00, 0x00 }, //148 +{ 0x00, 0x0c, 0x0c, 0x00, 0x00 }, //149 +{ 0x28, 0x28, 0x29, 0x2a, 0x3c }, //150 +{ 0x10, 0x11, 0x16, 0x14, 0x18 }, //151 +{ 0x02, 0x04, 0x0f, 0x10, 0x00 }, //152 +{ 0x0c, 0x08, 0x19, 0x09, 0x0e }, //153 +{ 0x09, 0x09, 0x0f, 0x09, 0x09 }, //154 +{ 0x09, 0x0a, 0x0c, 0x1f, 0x08 }, //155 +{ 0x08, 0x1f, 0x08, 0x0a, 0x0c }, //156 +{ 0x01, 0x09, 0x09, 0x0f, 0x01 }, //157 +{ 0x15, 0x15, 0x15, 0x1f, 0x00 }, //158 +{ 0x0c, 0x00, 0x0d, 0x01, 0x0e }, //159 +{ 0x04, 0x04, 0x04, 0x04, 0x04 }, //160 +{ 0x40, 0x41, 0x5e, 0x48, 0x70 }, //161 +{ 0x04, 0x08, 0x1f, 0x20, 0x40 }, //162 +{ 0x38, 0x20, 0x61, 0x22, 0x3c }, //163 +{ 0x11, 0x11, 0x1f, 0x11, 0x11 }, //164 +{ 0x22, 0x24, 0x28, 0x7f, 0x20 }, //165 +{ 0x21, 0x7e, 0x20, 0x21, 0x3e }, //166 +{ 0x28, 0x28, 0x7f, 0x28, 0x28 }, //167 +{ 0x08, 0x31, 0x21, 0x22, 0x3c }, //168 +{ 0x10, 0x60, 0x21, 0x3e, 0x20 }, //169 +{ 0x21, 0x21, 0x21, 0x21, 0x3f }, //170 +{ 0x20, 0x79, 0x22, 0x7c, 0x20 }, //171 +{ 0x29, 0x29, 0x01, 0x02, 0x1c }, //172 +{ 0x21, 0x22, 0x24, 0x2a, 0x31 }, //173 +{ 0x20, 0x7e, 0x21, 0x29, 0x31 }, //174 +{ 0x30, 0x09, 0x01, 0x02, 0x3c }, //175 +{ 0x08, 0x31, 0x29, 0x26, 0x3c }, //176 +{ 0x28, 0x29, 0x3e, 0x48, 0x08 }, //177 +{ 0x30, 0x00, 0x31, 0x02, 0x3c }, //178 +{ 0x10, 0x51, 0x5e, 0x50, 0x10 }, //179 +{ 0x00, 0x7f, 0x08, 0x04, 0x00 }, //180 +{ 0x11, 0x12, 0x7c, 0x10, 0x10 }, //181 +{ 0x01, 0x21, 0x21, 0x21, 0x01 }, //182 +{ 0x21, 0x2a, 0x24, 0x2a, 0x30 }, //183 +{ 0x22, 0x24, 0x6f, 0x34, 0x22 }, //184 +{ 0x00, 0x01, 0x02, 0x7c, 0x00 }, //185 +{ 0x0f, 0x00, 0x20, 0x10, 0x0f }, //186 +{ 0x7e, 0x11, 0x11, 0x11, 0x11 }, //187 +{ 0x20, 0x21, 0x21, 0x22, 0x3c }, //188 +{ 0x10, 0x20, 0x10, 0x08, 0x06 }, //189 +{ 0x26, 0x20, 0x7f, 0x20, 0x26 }, //190 +{ 0x20, 0x24, 0x22, 0x25, 0x38 }, //191 +{ 0x00, 0x2a, 0x2a, 0x2a, 0x01 }, //192 +{ 0x0e, 0x12, 0x22, 0x02, 0x07 }, //193 +{ 0x01, 0x0a, 0x04, 0x0a, 0x30 }, //194 +{ 0x28, 0x3e, 0x29, 0x29, 0x29 }, //195 +{ 0x10, 0x7f, 0x10, 0x14, 0x18 }, //196 +{ 0x01, 0x21, 0x21, 0x3f, 0x01 }, //197 +{ 0x29, 0x29, 0x29, 0x29, 0x3f }, //198 +{ 0x10, 0x50, 0x51, 0x52, 0x1c }, //199 +{ 0x78, 0x01, 0x02, 0x7c, 0x00 }, //200 +{ 0x1f, 0x00, 0x3f, 0x01, 0x06 }, //201 +{ 0x3f, 0x01, 0x02, 0x04, 0x08 }, //202 +{ 0x3f, 0x21, 0x21, 0x21, 0x3f }, //203 +{ 0x38, 0x20, 0x21, 0x22, 0x3c }, //204 +{ 0x21, 0x21, 0x01, 0x02, 0x0c }, //205 +{ 0x20, 0x10, 0x40, 0x20, 0x00 }, //206 +{ 0x70, 0x50, 0x70, 0x00, 0x00 }, //207 +{ 0x0e, 0x11, 0x09, 0x06, 0x19 }, //208 +{ 0x02, 0x55, 0x15, 0x55, 0x0f }, //209 +{ 0x1f, 0x2a, 0x2a, 0x2a, 0x14 }, //210 +{ 0x0a, 0x15, 0x15, 0x11, 0x02 }, //211 +{ 0x3f, 0x02, 0x02, 0x04, 0x3e }, //212 +{ 0x0e, 0x11, 0x19, 0x15, 0x12 }, //213 +{ 0x0f, 0x12, 0x22, 0x22, 0x1c }, //214 +{ 0x1c, 0x22, 0x22, 0x22, 0x3f }, //215 +{ 0x02, 0x01, 0x1e, 0x10, 0x10 }, //216 +{ 0x20, 0x20, 0x00, 0x70, 0x00 }, //217 +{ 0x00, 0x00, 0x10, 0x5f, 0x00 }, //218 +{ 0x28, 0x10, 0x28, 0x00, 0x00 }, //219 +{ 0x18, 0x24, 0x7e, 0x24, 0x08 }, //220 +{ 0x14, 0x7f, 0x15, 0x01, 0x01 }, //221 +{ 0x1f, 0x48, 0x50, 0x50, 0x0f }, //222 +{ 0x0e, 0x51, 0x11, 0x51, 0x0e }, //223 +{ 0x3f, 0x12, 0x22, 0x22, 0x1c }, //224 +{ 0x1c, 0x22, 0x22, 0x12, 0x3f }, //225 +{ 0x3c, 0x52, 0x52, 0x52, 0x3c }, //226 +{ 0x03, 0x05, 0x02, 0x05, 0x06 }, //227 +{ 0x1a, 0x26, 0x20, 0x26, 0x1a }, //228 +{ 0x1e, 0x41, 0x01, 0x42, 0x1f }, //229 +{ 0x63, 0x55, 0x49, 0x41, 0x41 }, //230 +{ 0x22, 0x3c, 0x20, 0x3e, 0x22 }, //231 +{ 0x51, 0x4a, 0x44, 0x4a, 0x51 }, //232 +{ 0x3c, 0x02, 0x02, 0x02, 0x3f }, //233 +{ 0x28, 0x28, 0x3e, 0x28, 0x48 }, //234 +{ 0x22, 0x3c, 0x28, 0x28, 0x2e }, //235 +{ 0x3e, 0x28, 0x38, 0x28, 0x3e }, //236 +{ 0x04, 0x04, 0x15, 0x04, 0x04 }, //237 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //238 +{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, //239 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //240 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //241 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //242 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //243 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //244 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //245 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //246 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //247 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //248 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //249 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //250 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //251 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //252 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //253 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //254 +{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //255 + }; + + +inline static bool displayBit( unsigned value, unsigned row, unsigned column ) +{ + assert( value < 256 ); + assert( row < 7 ); + assert( column < 5 ); + return characterMap[value][column] & (1 << row); +}; + + +Item* MatrixDisplayDriver::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new MatrixDisplayDriver( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem * MatrixDisplayDriver::libraryItem() +{ + return new LibraryItem( + "ec/matrix_display_driver", + i18n("Matrix Display Driver"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + MatrixDisplayDriver::construct ); +} + + +MatrixDisplayDriver::MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "Matrix Display Driver" ) +{ + m_name = i18n("Matrix Display Driver"); + + m_prevCol = 0; + m_nextCol = 0; + m_scanCount = 2; + + createProperty( "diode-configuration", Variant::Type::Select ); + property("diode-configuration")->setCaption( i18n("Configuration") ); + property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") ); + property("diode-configuration")->setValue("Row Cathode"); + property("diode-configuration")->setAdvanced(true); + + QStringList pins = QStringList::split( ',', "D0,D1,D2,D3,D4,D5,D6,D7,,,,,,C4,C3,C2,C1,C0,,R0,R1,R2,R3,R4,R5,R6", true ); + initDIPSymbol( pins, 64 ); + initDIP(pins); + + m_pValueLogic.resize( 8, 0l ); + for ( unsigned i = 0; i < 8; ++i ) + m_pValueLogic[i] = createLogicIn( ecNodeWithID("D"+QString::number(i)) ); + + m_pRowLogic.resize( 7, 0l ); + for ( unsigned i = 0; i < 7; ++i ) + { + m_pRowLogic[i] = createLogicOut( ecNodeWithID("R"+QString::number(i)), false ); + m_pRowLogic[i]->setOutputLowConductance( 1.0 ); + m_pRowLogic[i]->setOutputHighVoltage(5.0); + } + + m_pColLogic.resize( 5, 0l ); + for ( unsigned i = 0; i < 5; ++i ) + { + m_pColLogic[i] = createLogicOut( ecNodeWithID("C"+QString::number(i)), false ); + m_pColLogic[i]->setOutputHighVoltage(5.0); + } +} + + +MatrixDisplayDriver::~MatrixDisplayDriver() +{ +} + + +void MatrixDisplayDriver::stepNonLogic() +{ + if ( ++m_scanCount < 5 ) + return; + m_scanCount = 0; + + m_pColLogic[m_prevCol]->setHigh(false); + m_pColLogic[m_nextCol]->setHigh(true); + + unsigned value = 0; + for ( unsigned i = 0; i < 8; ++i ) + value |= ( m_pValueLogic[i]->isHigh() ) ? (1 << i) : 0; + + for ( unsigned row = 0; row < 7; row++ ) + { + m_pRowLogic[row]->setHigh( !displayBit( value, row, m_nextCol) ); + } + + m_prevCol = m_nextCol; + + m_nextCol++; + if ( m_nextCol >= 5 ) + m_nextCol = 0; +} + diff --git a/src/electronics/components/matrixdisplaydriver.h b/src/electronics/components/matrixdisplaydriver.h new file mode 100644 index 0000000..e6b01cc --- /dev/null +++ b/src/electronics/components/matrixdisplaydriver.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef MATRIXDISPLAYDRIVER_H +#define MATRIXDISPLAYDRIVER_H + +#include "matrixdisplay.h" + +/** +@author David Saxton + */ +class MatrixDisplayDriver : public Component +{ + public: + MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~MatrixDisplayDriver(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual bool canFlip() const { return true; } + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + QValueVector m_pValueLogic; + QValueVector m_pRowLogic; + QValueVector m_pColLogic; + + unsigned m_prevCol; + unsigned m_nextCol; + unsigned m_scanCount; +}; + +#endif diff --git a/src/electronics/components/meter.cpp b/src/electronics/components/meter.cpp new file mode 100644 index 0000000..4437794 --- /dev/null +++ b/src/electronics/components/meter.cpp @@ -0,0 +1,265 @@ +/*************************************************************************** + * 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 "canvasitemparts.h" +#include "ecnode.h" +#include "element.h" +#include "libraryitem.h" +#include "meter.h" +#include "variant.h" +#include "voltagesource.h" +#include "pin.h" +#include "simulator.h" + +#include +#include +#include + + +//BEGIN class Meter +Meter::Meter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + m_bDynamicContent = true; + b_timerStarted = false; + m_timeSinceUpdate = 0.; + m_old_value = 0.; + m_avgValue = 0.; + b_firstRun = true; + setSize( -16, -16, 32, 32 ); + + p_displayText = addDisplayText( "meter", QRect( -16, 16, 32, 16 ), displayText() ); + + createProperty( "0-minValue", Variant::Type::Double ); + property("0-minValue")->setCaption( i18n("Minimum Value") ); + property("0-minValue")->setMinValue(1e-12); + property("0-minValue")->setMaxValue(1e12); + property("0-minValue")->setValue(1e-3); + + createProperty( "1-maxValue", Variant::Type::Double ); + property("1-maxValue")->setCaption( i18n("Maximum Value") ); + property("1-maxValue")->setMinValue(1e-12); + property("1-maxValue")->setMaxValue(1e12); + property("1-maxValue")->setValue(1e3); +} + + +Meter::~Meter() +{ +} + + +void Meter::dataChanged() +{ + m_minValue = dataDouble("0-minValue"); + m_maxValue = dataDouble("1-maxValue"); + setChanged(); +} + +void Meter::stepNonLogic() +{ + if (b_firstRun) + { + p_displayText->setText(displayText()); + updateAttachedPositioning(); + setChanged(); + property("0-minValue")->setUnit(m_unit); + property("1-maxValue")->setUnit(m_unit); + b_firstRun = false; + } + + const double v = meterValue(); + if ( !b_timerStarted && std::abs(((v-m_old_value)/m_old_value)) > 1e-6 ) { + b_timerStarted = true; + } + + if (b_timerStarted) + { + m_timeSinceUpdate += 1./LINEAR_UPDATE_RATE; + m_avgValue += v/LINEAR_UPDATE_RATE; +// setChanged(); + if ( m_timeSinceUpdate > 0.05 ) + { + if ( p_displayText->setText(displayText()) ); + updateAttachedPositioning(); + } + } +} + +void Meter::drawShape( QPainter &p ) +{ + initPainter(p); + p.drawEllipse( (int)x()-16, (int)y()-16, width(), width() ); + p.setPen(QPen(Qt::black,2)); + p.setBrush(Qt::black); + + // The proportion between 0.1mV and 10KV, on a logarithmic scale + double prop; + const double abs_value = std::abs(m_old_value); + if ( abs_value <= m_minValue ) + prop = 0.; + else if ( abs_value >= m_maxValue ) + prop = 1.; + else + prop = std::log10( abs_value/m_minValue ) / std::log10( m_maxValue/m_minValue ); + if ( m_old_value>0 ) + prop *= -1; + double sin_prop = 10*std::sin(prop*1.571); // 1.571 = pi/2 + double cos_prop = 10*std::cos(prop*1.571); // 1.571 = pi/2 + + int cx = int(x()-16+(width()/2)); + int cy = int(y()-16+(height()/2)); + p.drawLine( int(cx-sin_prop), int(cy-cos_prop), int(cx+sin_prop), int(cy+cos_prop) ); + + QPointArray pa(3); + pa[0] = QPoint( int(cx-sin_prop), int(cy-cos_prop) ); // Arrow head + pa[1] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(-0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(-0.3+prop))) ); + pa[2] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(0.3+prop))) ); + p.drawPolygon(pa); + + deinitPainter(p); +} + + +QString Meter::displayText() +{ + double value = m_avgValue/m_timeSinceUpdate; + if ( !std::isfinite(value) ) value = m_old_value; + if ( std::abs((value)) < 1e-9 ) value = 0.; + m_old_value = value; + m_avgValue = 0.; + m_timeSinceUpdate = 0.; + b_timerStarted = false; + return QString::number( value/CNItem::getMultiplier(value), 'g', 3 ) + CNItem::getNumberMag(value) + m_unit; +} +//END class Meter + + +//BEGIN class FrequencyMeter +Item* FrequencyMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new FrequencyMeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* FrequencyMeter::libraryItem() +{ + return new LibraryItem( + QString("ec/frequencymeter"), + i18n("Frequency Meter (TODO)"), + i18n("Outputs"), + "frequencymeter.png", + LibraryItem::lit_component, + FrequencyMeter::construct ); +} + +FrequencyMeter::FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "frequencymeter" ) +{ + m_name = i18n("Frequency Meter"); + m_desc = i18n("Place this at the point where frequency is to be measured."); + m_unit = "Hz"; + + m_probeNode = createPin( 0, -24, 90, "n1" ); +} + +FrequencyMeter::~FrequencyMeter() +{ +} + +double FrequencyMeter::meterValue() +{ + return 0; +} +//END class FrequencyMeter + + +//BEGIN class ECAmmeter +Item* ECAmmeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECAmmeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECAmmeter::libraryItem() +{ + QStringList ids; + ids << "ec/ammeter" << "ec/ammmeter"; + return new LibraryItem( + ids, + i18n("Ammeter"), + i18n("Outputs"), + "ammeter.png", + LibraryItem::lit_component, + ECAmmeter::construct + ); +} + +ECAmmeter::ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "ammeter" ) +{ + m_name = i18n("Ammeter"); + m_desc = i18n("Place this in series in the circuit to measure the current flowing."); + setSize( -16, -16, 32, 32 ); + m_unit = "A"; + + init1PinLeft(0); + init1PinRight(0); + + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. ); +} + +ECAmmeter::~ECAmmeter() +{ +} + +double ECAmmeter::meterValue() +{ + return -m_voltageSource->cbranchCurrent(0); +} +//END class ECAmmeter + + +//BEGIN class ECVoltmeter +Item* ECVoltMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECVoltMeter( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECVoltMeter::libraryItem() +{ + return new LibraryItem( + QString("ec/voltmeter"), + i18n("Voltmeter"), + i18n("Outputs"), + "voltmeter.png", + LibraryItem::lit_component, + ECVoltMeter::construct ); +} + +ECVoltMeter::ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id ) + : Meter( icnDocument, newItem, (id) ? id : "voltmeter" ) +{ + m_name = i18n("Voltmeter"); + m_desc = i18n("Place this in parallel in the circuit to meaure the voltage between two points."); + m_unit = "V"; + + init1PinLeft(0); + init1PinRight(0); +} + +ECVoltMeter::~ECVoltMeter() +{ +} + +double ECVoltMeter::meterValue() +{ + return m_pNNode[0]->pin()->voltage() - m_pPNode[0]->pin()->voltage(); +} +//END class ECVoltMeter + diff --git a/src/electronics/components/meter.h b/src/electronics/components/meter.h new file mode 100644 index 0000000..fa52e95 --- /dev/null +++ b/src/electronics/components/meter.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef METER_H +#define METER_H + +#include + +/** +@author David Saxton +*/ +class Meter : public Component +{ +public: + Meter( ICNDocument *icnDocument, bool newItem, const char *id ); + ~Meter(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + virtual void drawShape( QPainter &p ); + +protected: + QString displayText(); + virtual void dataChanged(); + /** + * Return the value / current, or whatever the meter is measuring + */ + virtual double meterValue() = 0; + + bool b_firstRun; // If true, then update the text dispalyed + bool b_timerStarted; // The timer to change the text is started on change + double m_timeSinceUpdate; + double m_avgValue; + double m_old_value; + double m_minValue; + double m_maxValue; + Text *p_displayText; + QString m_unit; +}; + +/** +@short Measures the frequency at a point in the circuit +@author David Saxton +*/ +class FrequencyMeter : public Meter +{ +public: + FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FrequencyMeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); + ECNode *m_probeNode; +}; + +/** +@short Simple resistor +@author David Saxton +*/ +class ECAmmeter : public Meter +{ +public: + ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECAmmeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); + +private: + VoltageSource *m_voltageSource; +}; + +/** +@short Displays voltage across terminals +@author David Saxton +*/ +class ECVoltMeter : public Meter +{ +public: + ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECVoltMeter(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + virtual double meterValue(); +}; + +#endif diff --git a/src/electronics/components/multiinputgate.cpp b/src/electronics/components/multiinputgate.cpp new file mode 100644 index 0000000..7453845 --- /dev/null +++ b/src/electronics/components/multiinputgate.cpp @@ -0,0 +1,530 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "ecnode.h" +#include "icndocument.h" +#include "libraryitem.h" +#include "multiinputgate.h" +#include "logic.h" + +#include +#include +#include + +//BEGIN class MultiInputGate +MultiInputGate::MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth ) + : Component( icnDocument, newItem, id ) +{ + b_doneInit = false; + m_numInputs = 0; + if ( baseWidth == -1 ) { + baseWidth = 32; + } + m_baseWidth = baseWidth; + + for ( int i=0; isetCaption( i18n("Number Inputs") ); + property("numInput")->setMinValue(2); + property("numInput")->setMaxValue(maxGateInput); + property("numInput")->setValue(2); + + b_doneInit = true; +} + + +MultiInputGate::~MultiInputGate() +{ +} + + +void MultiInputGate::dataChanged() +{ + updateInputs( QMIN( maxGateInput, dataInt("numInput") ) ); +} + + +void MultiInputGate::updateInputs( int newNum ) +{ + if ( newNum == m_numInputs ) { + return; + } + + if ( newNum < 2 ) { + newNum = 2; + } + else if ( newNum > maxGateInput ) { + newNum = maxGateInput; + } + + const int newWidth = m_baseWidth; + + setSize( -newWidth/2, -8*newNum, newWidth, 16*newNum, true ); + + const bool added = ( newNum > m_numInputs ); + if (added) + { + for ( int i = m_numInputs; isetCallback( this, (CallbackPtr)(&MultiInputGate::inStateChanged) ); + } + } + else + { + for ( int i=newNum; iisHigh() ) + highCount++; + } + + m_pOut->setHigh( highCount != 1 ); +} + +void ECXnor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+22, _y, 2*width()-28, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+22, _y, 2*width()-28, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + p.drawArc( _x, _y, 16, height(), -16*90, 16*180 ); + + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECXnor + + +//BEGIN class ECXor +Item* ECXor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECXor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECXor::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/xor"), + i18n("XOR gate"), + i18n("Logic"), + "xor.png", + LibraryItem::lit_component, + ECXor::construct ); +} + +ECXor::ECXor( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "xor", 48 ) +{ + m_name = i18n("XOR gate"); + m_desc = i18n("Exclusive OR gate. Output is high when exactly one input is high."); + + inStateChanged(false); +} + +ECXor::~ECXor() +{ +} + +void ECXor::inStateChanged(bool) +{ + int highCount = 0; + for ( int i=0; iisHigh() ) + highCount++; + } + + m_pOut->setHigh( highCount == 1 ); +} + +void ECXor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+16, _y, 2*width()-16, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+16, _y, 2*width()-16, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + p.drawArc( _x, _y, 16, height(), -16*90, 16*180 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECXor + + +//BEGIN class EXOr +Item* ECOr::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECOr( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECOr::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/or"), + i18n("OR gate"), + i18n("Logic"), + "or.png", + LibraryItem::lit_component, + ECOr::construct ); +} + +ECOr::ECOr( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "or", 48 ) +{ + m_name = i18n("OR gate"); + m_desc = i18n("The output is high when at least one of the inputs is high; or low when all of the inputs are off"); + + inStateChanged(false); +} + +ECOr::~ECOr() +{ +} + +void ECOr::inStateChanged(bool) +{ + bool allLow = true; + for ( int i=0; iisHigh() ) + allLow = false; + } + + m_pOut->setHigh(!allLow); +} + +void ECOr::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); +// p.setBrush( Qt::red ); + p.drawChord( _x-width(), _y, 2*width(), height(), -16*81, 16*162 ); +// p.drawPie( _x-width()+16, _y, 2*width()-16, height(), -16*100, 16*200 ); + p.restore(); + + p.drawArc( _x-width(), _y, 2*width(), height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECOr + + +//BEGIN class ECNor +Item* ECNor::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECNor( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECNor::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/nor"), + i18n("NOR gate"), + i18n("Logic"), + "nor.png", + LibraryItem::lit_component, + ECNor::construct ); +} + +ECNor::ECNor( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, (id) ? id : "nor", 48 ) +{ + m_name = i18n("NOR Gate"); + m_desc = i18n("The output is high when all inputs are low."); + + inStateChanged(false); +} + +ECNor::~ECNor() +{ +} + +void ECNor::inStateChanged(bool) +{ + bool allLow = true; + for ( int i=0; iisHigh() ) + allLow = false; + } + + m_pOut->setHigh(allLow); +} + +void ECNor::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*81, 16*162 ); + p.restore(); + + p.drawArc( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 ); + p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 ); + + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + + const int n = m_numInputs; + for ( int i=0; iisSelected() ? m_selectedCol : Qt::black ); + int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n; + p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 ); + } + + deinitPainter(p); +} +//END class ECNor + + +//BEGIN class ECNand +Item* ECNand::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECNand( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECNand::libraryItem() +{ + return new LibraryItem( + QString::QString("ec/nand"), + i18n("NAND gate"), + i18n("Logic"), + "nand.png", + LibraryItem::lit_component, + ECNand::construct ); +} + +ECNand::ECNand( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, id ? id : "nand" ) +{ + m_name = i18n("NAND Gate"); + m_desc = i18n("The output is low only when all of the inputs are high."); + + inStateChanged(false); +} + +ECNand::~ECNand() +{ +} + +void ECNand::inStateChanged(bool) +{ + bool allHigh = true; + for ( int i=0; iisHigh() ) + allHigh = false; + } + + m_pOut->setHigh(!allHigh); +} + +void ECNand::drawShape( QPainter &p ) +{ + initPainter(p); + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 ); + p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 ); + deinitPainter(p); +} +//END class ECNand + + +//BEGIN class ECAnd +Item* ECAnd::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECAnd( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECAnd::libraryItem() +{ + QStringList idList; + idList << "ec/and" << "ec/and_2"; + return new LibraryItem( + idList, + i18n("AND gate"), + i18n("Logic"), + "and.png", + LibraryItem::lit_component, + ECAnd::construct ); +} + +ECAnd::ECAnd( ICNDocument *icnDocument, bool newItem, const char *id ) + : MultiInputGate( icnDocument, newItem, id ? id : "and" ) +{ + m_name = i18n("AND Gate"); + m_desc = i18n("The output is high if and only if all of the inputs are high."); + + inStateChanged(false); +} + +ECAnd::~ECAnd() +{ +} + +void ECAnd::inStateChanged(bool) +{ + bool allHigh = true; + for ( int i=0; iisHigh() ) + allHigh = false; + } + + m_pOut->setHigh(allHigh); +} + +void ECAnd::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()+offsetX(); + int _y = (int)y()+offsetY(); + p.drawChord( _x-width(), _y, 2*width(), height(), -16*90, 16*180 ); + + deinitPainter(p); +} +//END class ECAnd diff --git a/src/electronics/components/multiinputgate.h b/src/electronics/components/multiinputgate.h new file mode 100644 index 0000000..1981217 --- /dev/null +++ b/src/electronics/components/multiinputgate.h @@ -0,0 +1,160 @@ +/*************************************************************************** + * Copyright (C) 2004-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. * + ***************************************************************************/ + +#ifndef MULTIINPUTGATE_H +#define MULTIINPUTGATE_H + +#include "component.h" +#include "logic.h" + +const int maxGateInput = 256; + +/** +@author David Saxton +*/ +class MultiInputGate : public CallbackClass, public Component +{ +public: + MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth = -1 ); + ~MultiInputGate(); + +protected: + virtual void inStateChanged( bool newState ) = 0; + void dataChanged(); + void updateInputs( int newNum ); + + int m_numInputs; + int m_baseWidth; + + LogicIn *inLogic[maxGateInput]; + ECNode *inNode[maxGateInput]; + + LogicOut * m_pOut; + + virtual void updateAttachedPositioning(); + +private: + bool b_doneInit; +}; + + +/** +@short Boolean XNOR +@author David Saxton +*/ +class ECXnor : public MultiInputGate +{ +public: + ECXnor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECXnor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + +/** +@short Boolean XOR +@author David Saxton +*/ +class ECXor : public MultiInputGate +{ +public: + ECXor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECXor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + +/** +@short Boolean OR +@author David Saxton +*/ +class ECOr : public MultiInputGate +{ +public: + ECOr( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECOr(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean NOR +@author David Saxton +*/ +class ECNor : public MultiInputGate +{ +public: + ECNor( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECNor(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean NAND +@author David Saxton +*/ +class ECNand : public MultiInputGate +{ +public: + ECNand( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECNand(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + +/** +@short Boolean AND +@author David Saxton +*/ +class ECAnd : public MultiInputGate +{ +public: + ECAnd( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECAnd(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +private: + void inStateChanged( bool newState ); + virtual void drawShape( QPainter &p ); +}; + + + +#endif diff --git a/src/electronics/components/multiplexer.cpp b/src/electronics/components/multiplexer.cpp new file mode 100644 index 0000000..e421fee --- /dev/null +++ b/src/electronics/components/multiplexer.cpp @@ -0,0 +1,176 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "multiplexer.h" + +#include "logic.h" +#include "libraryitem.h" + +#include +#include + +#include + +Item* Multiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Multiplexer( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Multiplexer::libraryItem() +{ + return new LibraryItem( + QString("ec/multiplexer"), + i18n("Multiplexer"), + i18n("Integrated Circuits"), + "ic1.png", + LibraryItem::lit_component, + Multiplexer::construct + ); +} + +Multiplexer::Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "multiplexer" ) +{ + m_name = i18n("Multiplexer"); + m_desc = i18n("Combines the input data stream into one single stream. The value of the input selected by the \"A\" inputs is passed to the output."); + + m_output = 0l; + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(8); + property("addressSize")->setValue(1); + + // For backwards compatibility + createProperty( "numInput", Variant::Type::Int ); + property("numInput")->setMinValue(-1); + property("numInput")->setValue(-1); + property("numInput")->setHidden(true); +} + +Multiplexer::~Multiplexer() +{ +} + + +void Multiplexer::dataChanged() +{ + if ( hasProperty("numInput") && dataInt("numInput") != -1 ) + { + int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) ); + property("numInput")->setValue(-1); + + if ( addressSize < 1 ) + addressSize = 1; + else if ( addressSize > 8 ) + addressSize = 8; + + // This function will get called again when we set the value of numInput + property("addressSize")->setValue(addressSize); + return; + } + + if ( hasProperty("numInput") ) + { + m_variantData["numInput"]->deleteLater(); + m_variantData.remove("numInput"); + } + + initPins( unsigned(dataInt("addressSize")) ); +} + + +void Multiplexer::inStateChanged( bool /*state*/ ) +{ + unsigned long long pos = 0; + for ( unsigned i = 0; i < m_aLogic.size(); ++i ) + { + if ( m_aLogic[i]->isHigh() ) + pos += 1 << i; + } + m_output->setHigh( m_xLogic[pos]->isHigh() ); +} + + +void Multiplexer::initPins( unsigned newAddressSize ) +{ + unsigned oldAddressSize = m_aLogic.size(); + unsigned long long oldXLogicCount = m_xLogic.size(); + unsigned long long newXLogicCount = 1 << newAddressSize; + + if ( newXLogicCount == oldXLogicCount ) + return; + + QStringList pins; + + const int length = newAddressSize + newXLogicCount; + + for ( unsigned i=0; i oldXLogicCount ) + { + m_xLogic.resize(newXLogicCount); + for ( unsigned i=oldXLogicCount; isetCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) ); + } + + m_aLogic.resize(newAddressSize); + for ( unsigned i=oldAddressSize; isetCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) ); + } + } + else + { + for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i ) + { + QString id = "X"+QString::number(i); + removeDisplayText(id); + removeElement( m_xLogic[i], false ); + removeNode(id); + } + m_xLogic.resize(newXLogicCount); + + for ( unsigned i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = "A"+QString::number(i); + removeDisplayText(id); + removeElement( m_aLogic[i], false ); + removeNode(id); + } + m_aLogic.resize(newAddressSize); + } +} + diff --git a/src/electronics/components/multiplexer.h b/src/electronics/components/multiplexer.h new file mode 100644 index 0000000..42bcfc1 --- /dev/null +++ b/src/electronics/components/multiplexer.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2004-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. * + ***************************************************************************/ + +#ifndef MULTIPLEXER_H +#define MULTIPLEXER_H + +#include "component.h" +#include "logic.h" + +#include + +/** +@author David Saxton +*/ +class Multiplexer : public CallbackClass, public Component +{ +public: + Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Multiplexer(); + + virtual bool canFlip() const { return true; } + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + +protected: + void dataChanged(); + /** + * Add / remove pins according to the number of inputs the user has requested + */ + void initPins( unsigned addressSize ); + + void inStateChanged( bool newState ); + + QPtrVector m_aLogic; + QPtrVector m_xLogic; + LogicOut * m_output; +}; + +#endif diff --git a/src/electronics/components/parallelportcomponent.cpp b/src/electronics/components/parallelportcomponent.cpp new file mode 100644 index 0000000..9bc17b4 --- /dev/null +++ b/src/electronics/components/parallelportcomponent.cpp @@ -0,0 +1,241 @@ +/*************************************************************************** + * 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 "port.h" +#include "parallelportcomponent.h" + +#include "ecnode.h" +#include "itemdocument.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include +#include +#include + +#include +#include + +Item* ParallelPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ParallelPortComponent( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ParallelPortComponent::libraryItem() +{ + return new LibraryItem( + "ec/parallel_port", + i18n("Parallel Port"), + i18n("Connections"), + "ic1.png", + LibraryItem::lit_component, + ParallelPortComponent::construct + ); +} + +ParallelPortComponent::ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "parallel_port" ) +{ + m_name = i18n("Parallel Port"); + m_desc = i18n("The pins are divided into 3 registers.

" + "Data Pins

" + "The data pins can be configured as either all input or all output. They are:" + "
    " + "
  • D[0..7]
  • " + "

" + "Status Pins

" + "The status pins are read-only. They area:" + "
    " + "
  • ERR - Error
  • " + "
  • ON - Online
  • " + "
  • PE - Paper End
  • " + "
  • ACK - Acknowledge
  • " + "
  • BUSY - Busy
  • " + "

" + "Control Pins" + "
    " + "
  • STR - Strobe
  • " + "
  • AUT - Auto Feed
  • " + "
  • INIT - Init
  • " + "
  • SEL - Select
  • " + "

" + "The remaining pins are all ground." + ); + + QPointArray pa( 4 ); + pa[0] = QPoint( -32, -112 ); + pa[1] = QPoint( 32, -104 ); + pa[2] = QPoint( 32, 104 ); + pa[3] = QPoint( -32, 112 ); + setItemPoints( pa ); + + m_pParallelPort = new ParallelPort(); + + for ( unsigned i = 0; i < 24; ++i ) + m_pLogic[i] = 0; + + ECNode * pin = 0; + + //BEGIN Data register + for ( int i = 0; i < 8; ++i ) + { + QString id = QString("D%1").arg(i); + QString name = id; + + pin = createPin( -40, -80 + 16*i, 0, id ); + addDisplayText( id, QRect( -28, -88 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + + m_pLogic[i] = createLogicOut( pin, false ); + m_pLogic[i]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::dataCallback) ); + } + //END Data register + + + //BEGIN Status register + QString statusNames[] = { "ERR", "ON", "PE", "ACK", "BUSY" }; + + // The statusIDs are referenced in the save file and must not change + QString statusIDs[] = { "ERROR", "ONLINE", "PE", "ACK", "BUSY" }; + + // Bits 0...2 in the Status register are not used + for ( int i = 3; i < 8; ++i ) + { + QString id = statusIDs[i-3]; + QString name = statusNames[i-3]; + + // Bit 3 (pin 15) doesn't not follow the same positioning pattern as + // the other pins in the Status register. + if ( i == 3 ) + { + pin = createPin( 40, -72, 180, id ); + addDisplayText( id, QRect( 0, -80, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + else + { + pin = createPin( -40, -16 + 16*i, 0, id ); + addDisplayText( id, QRect( -28, -24 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + } + + m_pLogic[i+8] = createLogicOut( pin, false ); + } + //END Status register + + + //BEGIN Control register + QString controlNames[] = { "STR", "AUT", "INIT", "SEL" }; + + // The controlIDs are referenced in the save file and must not change + QString controlIDs[] = { "STROBE", "AUTO", "INIT", "SELECT" }; + + // Bits 4..7 are not used (well; bit 5 is, but not as a pin) + for ( int i = 0; i < 4; ++i ) + { + QString id = controlIDs[i]; + QString name = controlNames[i]; + + if ( i == 0 ) + { + pin = createPin( -40, -96, 0, id ); + addDisplayText( id, QRect( -28, -104, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter ); + } + else if ( i == 1 ) + { + pin = createPin( 40, -88, 180, id ); + addDisplayText( id, QRect( 0, -96, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + else + { + pin = createPin( 40, -88 + i*16, 180, id ); + addDisplayText( id, QRect( 0, -96 + i*16, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter ); + } + + m_pLogic[i+16] = createLogicOut( pin, false ); + m_pLogic[i+16]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::controlCallback) ); + } + //END Control register + + +#if 0 + // And make the rest of the pins ground + for ( int i = 0; i < 8; ++i ) + { + pin = createPin( 40, -24 + i*16, 180, QString("GND%1").arg( i ) ); + pin->pin()->setGroundType( Pin::gt_always ); + } +#endif + + Variant * v = createProperty( "port", Variant::Type::Combo ); + v->setAllowed( ParallelPort::ports( Port::ExistsAndRW ) ); + v->setCaption( i18n("Port") ); +} + + +ParallelPortComponent::~ParallelPortComponent() +{ + delete m_pParallelPort; +} + + +void ParallelPortComponent::dataChanged() +{ + initPort( dataString("port") ); +} + + +void ParallelPortComponent::initPort( const QString & port ) +{ + if ( port.isEmpty() ) + { + m_pParallelPort->closePort(); + return; + } + + if ( ! m_pParallelPort->openPort( port ) ) + { + p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) ); + return; + } +} + + +void ParallelPortComponent::dataCallback( bool ) +{ + uchar value = 0; + for ( unsigned i = 0; i < 8; ++ i ) + value |= m_pLogic[ i + 0 ]->isHigh() ? 0 : (1 << i); + + m_pParallelPort->writeToData( value ); +} + + +void ParallelPortComponent::controlCallback( bool ) +{ + uchar value = 0; + for ( unsigned i = 0; i < 4; ++ i ) + value |= m_pLogic[ i + 16 ]->isHigh() ? 0 : (1 << i); + + m_pParallelPort->writeToControl( value ); +} + + +void ParallelPortComponent::stepNonLogic() +{ + uchar status = m_pParallelPort->readFromRegister( ParallelPort::Status ); + // Bits 0...2 in the Status register are not used + for ( int i = 3; i < 8; ++i ) + m_pLogic[i + 8]->setHigh( status | (1 << i) ); +} + + +void ParallelPortComponent::drawShape( QPainter & p ) +{ + drawPortShape( p ); +} diff --git a/src/electronics/components/parallelportcomponent.h b/src/electronics/components/parallelportcomponent.h new file mode 100644 index 0000000..89ead80 --- /dev/null +++ b/src/electronics/components/parallelportcomponent.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef PARALLELPORTCOMPONENT_H +#define PARALLELPORTCOMPONENT_H + +#include "logic.h" +#include "component.h" + +class ParallelPort; + +/** +@author David Saxton + */ +class ParallelPortComponent : public CallbackClass, public Component +{ + public: + ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ParallelPortComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + void initPort( const QString & port ); + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + void dataCallback( bool ); + void controlCallback( bool ); + + /// Registers: { Data[0...7], Status[0...5], 0[6...7], Control[0...4], 0[5...7] } + LogicOut * m_pLogic[24]; + + ParallelPort * m_pParallelPort; +}; + +#endif diff --git a/src/electronics/components/piccomponent.cpp b/src/electronics/components/piccomponent.cpp new file mode 100644 index 0000000..47320bb --- /dev/null +++ b/src/electronics/components/piccomponent.cpp @@ -0,0 +1,437 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "config.h" +#ifndef NO_GPSIM + +#include "canvasitemparts.h" +#include "circuitdocument.h" +#include "docmanager.h" +#include "gpsimprocessor.h" +#include "libraryitem.h" +#include "logic.h" +#include "ktechlab.h" +#include "micropackage.h" +#include "picinfo.h" +#include "microlibrary.h" +#include "piccomponent.h" +#include "piccomponentpin.h" +#include "projectmanager.h" + +#include +#include +#include +#include +#include +#include + +#include "gpsim/ioports.h" +#include "gpsim/pic-processor.h" + +const QString _def_PICComponent_fileName = i18n(""); + + +Item* PICComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new PICComponent( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* PICComponent::libraryItem() +{ + QStringList IDs; + IDs << "ec/pic" << "ec/picitem" << "ec/picitem_18pin"; + + return new LibraryItem( + IDs, + "PIC", + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + PICComponent::construct ); +} + +PICComponent::PICComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "pic" ) +{ + m_name = i18n("PIC Micro"); + m_desc = i18n("The PIC component allows the simulation of a PIC program.

" + "The loadable PIC program must be one of the following formats:" + "
  • Assembly (.asm)
  • " + "
  • FlowCode (.flowcode)
  • " + "
  • Symbol file (.cod)
  • " + "
  • Microbe (.microbe, .basic)
  • " + "
  • C source (.c)
" + "Doubleclick on the PIC component to open up the program source file.

" + "If the program source file is of type assembly, then the the opened text file will automatically be linked to the simulation. " + "You can control the program from the text document using the debug controls.

" + "Explanation of buttons:" + "
  • Play - Run the PIC program from the point at which it was paused, or from the start otherwise.
  • " + "
  • Pause - Pause the simulation at the current execution point.
  • " + "
  • Stop - Reset all parts of the simulation.
  • " + "
  • Reload - Reread the PIC program from disk and restart gpsim.
"); + + m_bCreatedInitialPackage = false; + m_bLoadingProgram = false; + m_pGpsim = 0L; + + addButton( "run", QRect(), KGlobal::iconLoader()->loadIcon( "player_play", KIcon::Small ) ); + addButton( "pause", QRect(), KGlobal::iconLoader()->loadIcon( "player_pause", KIcon::Small ) ); + addButton( "reset", QRect(), KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ) ); + addButton( "reload", QRect(), KGlobal::iconLoader()->loadIcon( "reload", KIcon::Small ) ); + + if ( icnDocument->ktechlab() ) + connect( icnDocument->ktechlab(), SIGNAL(recentFileAdded(const KURL &)), this, SLOT(slotUpdateFileList()) ); + + connect( ProjectManager::self(), SIGNAL(projectOpened()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectClosed()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(projectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(subprojectCreated()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesAdded()), this, SLOT(slotUpdateFileList()) ); + connect( ProjectManager::self(), SIGNAL(filesRemoved()), this, SLOT(slotUpdateFileList()) ); + + createProperty( "program", Variant::Type::FileName ); + property("program")->setCaption( i18n("Program") ); + property("program")->setFilter("*.flowcode *.asm *.cod *.basic|All Supported Files\n*.flowcode|FlowCode (*.flowcode)\n*.cod|Symbol File (*.cod)\n*.asm|Assembly Code (*.asm)\n*.basic *.microbe|Microbe (*.basic, *.microbe)\n*.c|C (*.c)*|All Files"); + + // Used for restoring the pins on file loading before we have had a change + // to compile the PIC program + createProperty( "lastPackage", Variant::Type::String ); + property("lastPackage")->setHidden( true ); + +// //HACK This is to enable loading with pre-0.3 files (which didn't set a "lastPackage" +// // property). This will allow a P16F84 PIC to be initialized (which agrees with pre-0.3 +// // behaviour), but it will also load it if + + // This to allow loading of the PIC component from pre-0.3 files (which didn't set a + // "lastPackage" property). + if ( !newItem ) + property("lastPackage")->setValue("P16F84"); + + slotUpdateFileList(); + slotUpdateBtns(); + + initPackage( 0 ); +} + + +PICComponent::~PICComponent() +{ + deletePICComponentPins(); + delete m_pGpsim; +} + + +void PICComponent::dataChanged() +{ + initPIC(false); +} + + +void PICComponent::initPIC( bool forceReload ) +{ + if ( !m_bCreatedInitialPackage ) + { + // We are still being created, so other connectors will be expecting us to + // have grown pins soonish. + MicroInfo * microInfo = MicroLibrary::self()->microInfoWithID( dataString("lastPackage") ); + if ( microInfo ) + initPackage( microInfo ); + } + + QString newProgram = KURL( dataString("program") ).path(); + bool newFile = (m_picFile != newProgram); + if ( !newFile && !forceReload ) + return; + + delete m_pGpsim; + m_pGpsim = 0L; + + switch ( GpsimProcessor::isValidProgramFile(newProgram) ) + { + case GpsimProcessor::DoesntExist: + if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() ) + break; + KMessageBox::sorry( 0l, i18n("The file \"%1\" does not exist.").arg( newProgram ) ); + m_picFile = QString::null; + break; + + case GpsimProcessor::IncorrectType: + if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() ) + break; + KMessageBox::sorry( 0L, i18n("\"%1\" is not a valid PIC program.\nThe file must exist, and the extension should be \".cod\", \".asm\", \".flowcode\", \".basic\", \".microbe\" or \".c\".\n\".hex\" is allowed, provided that there is a corresponding \".cod\" file.").arg(newProgram) ); + m_picFile = QString::null; + break; + + case GpsimProcessor::Valid: + m_picFile = newProgram; + m_symbolFile = createSymbolFile(); + break; + } + + slotUpdateBtns(); +} + + +void PICComponent::deletePICComponentPins() +{ + const PICComponentPinMap::iterator picComponentMapEnd = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != picComponentMapEnd; ++it ) + delete it.data(); + m_picComponentPinMap.clear(); +} + + +void PICComponent::initPackage( MicroInfo * microInfo ) +{ + MicroPackage * microPackage = microInfo ? microInfo->package() : 0l; + + if ( microPackage ) + { + m_bCreatedInitialPackage = true; + + //BEGIN Get pin IDs + QStringList allPinIDs = microPackage->pinIDs(); + QStringList ioPinIDs = microPackage->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + + // Now, we make the unwanted pin ids blank, so a pin is not created for them + const QStringList::iterator allPinIDsEnd = allPinIDs.end(); + for ( QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it ) + { + if ( !ioPinIDs.contains(*it) ) + *it = ""; + } + //END Get pin IDs + + + //BEGIN Remove old stuff + // Remove old text + TextMap textMapCopy = m_textMap; + const TextMap::iterator textMapEnd = textMapCopy.end(); + for ( TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it ) + removeDisplayText(it.key()); + + // Remove the old pins + deletePICComponentPins(); + + // Remove old nodes + NodeMap nodeMapCopy = m_nodeMap; + const NodeMap::iterator nodeMapEnd = nodeMapCopy.end(); + for ( NodeMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it ) + { + if ( !ioPinIDs.contains(it.key()) ) + removeNode( it.key() ); + } + + removeElements(); + //END Remove old stuff + + + + //BEGIN Create new stuff + initDIPSymbol( allPinIDs, 80 ); + initDIP(allPinIDs); + + PicPinMap picPinMap = microPackage->pins( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + const PicPinMap::iterator picPinMapEnd = picPinMap.end(); + for ( PicPinMap::iterator it = picPinMap.begin(); it != picPinMapEnd; ++it ) + m_picComponentPinMap[it.key()] = new PICComponentPin( this, it.data() ); + //END Create new stuff + + + removeDisplayText( "no_file" ); + addDisplayText( "picid", QRect(offsetX(), offsetY()-16, width(), 16), microInfo->id() ); + } + else + { + setSize( -48, -72, 96, 144 ); + removeDisplayText( "picid" ); + addDisplayText( "no_file", sizeRect(), i18n("(No\nprogram\nloaded)") ); + } + + + //BEGIN Update button positions + int leftpos = (width()-88)/2+offsetX(); + button("run")->setOriginalRect( QRect( leftpos, height()+4+offsetY(), 20, 20 ) ); + button("pause")->setOriginalRect( QRect( leftpos+23, height()+4+offsetY(), 20, 20 ) ); + button("reset")->setOriginalRect( QRect( leftpos+46, height()+4+offsetY(), 20, 20 ) ); + button("reload")->setOriginalRect( QRect( leftpos+69, height()+4+offsetY(), 20, 20 ) ); + updateAttachedPositioning(); + //END Update button positions +} + + +void PICComponent::attachPICComponentPins() +{ + if ( !m_pGpsim || !m_pGpsim->picProcessor() ) + return; + + pic_processor * picProcessor = m_pGpsim->picProcessor(); + + const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it ) + it.data()->attach( picProcessor->get_pin( it.key() ) ); +} + + +void PICComponent::slotUpdateFileList() +{ + QStringList preFileList; + if ( p_icnDocument && p_icnDocument->ktechlab() ) + preFileList += p_icnDocument->ktechlab()->recentFiles(); + + QStringList fileList; + + if ( ProjectInfo * info = ProjectManager::self()->currentProject() ) + { + const KURL::List urls = info->childOutputURLs( ProjectItem::AllTypes, ProjectItem::ProgramOutput ); + KURL::List::const_iterator urlsEnd = urls.end(); + for ( KURL::List::const_iterator it = urls.begin(); it != urlsEnd; ++it ) + fileList << (*it).path(); + } + + const QStringList::iterator end = preFileList.end(); + for ( QStringList::iterator it = preFileList.begin(); it != end; ++it ) + { + QString file = KURL(*it).path(); + if ( (file.endsWith(".flowcode") || file.endsWith(".asm") || file.endsWith(".cod") || file.endsWith(".basic") || file.endsWith(".microbe") ) && !fileList.contains(file) ) { + fileList.append(file); + } + } + + QString fileName = dataString("program"); + + property("program")->setAllowed(fileList); + property("program")->setValue( fileName.isEmpty() ? _def_PICComponent_fileName : fileName ); +} + + +void PICComponent::buttonStateChanged( const QString &id, bool state ) +{ + if (!state) + return; + + if ( id == "reload" ) + { + programReload(); + return; + } + + if (!m_pGpsim) + return; + + if ( id == "run" ) + m_pGpsim->setRunning(true); + + else if ( id == "pause" ) + m_pGpsim->setRunning(false); + + else if ( id == "reset" ) + { + m_pGpsim->reset(); + + // Set all pin outputs to low + const PICComponentPinMap::iterator end = m_picComponentPinMap.end(); + for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it ) + it.data()->resetOutput(); + } + + slotUpdateBtns(); +} + + +bool PICComponent::mouseDoubleClickEvent ( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + if ( m_picFile.isEmpty() || (m_picFile == _def_PICComponent_fileName) ) + return false; + + (void) DocManager::self()->openURL(m_picFile); + + return true; +} + + +QString PICComponent::createSymbolFile() +{ + m_bLoadingProgram = true; + slotUpdateBtns(); + + return GpsimProcessor::generateSymbolFile( dataString("program"), this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed()) ); +} + + +void PICComponent::slotCODCreationSucceeded() +{ + m_bLoadingProgram = false; + + delete m_pGpsim; + m_pGpsim = new GpsimProcessor(m_symbolFile); + + if ( m_pGpsim->codLoadStatus() == GpsimProcessor::CodSuccess ) + { + MicroInfo * microInfo = m_pGpsim->microInfo(); + property("lastPackage")->setValue( microInfo->id() ); + initPackage( microInfo ); + + connect( m_pGpsim, SIGNAL(runningStatusChanged(bool )), this, SLOT(slotUpdateBtns()) ); + attachPICComponentPins(); + } + + else + { + m_pGpsim->displayCodLoadStatus(); + delete m_pGpsim; + m_pGpsim = 0l; + } + + slotUpdateBtns(); +} + + +void PICComponent::slotCODCreationFailed() +{ + m_bLoadingProgram = false; + slotUpdateBtns(); +} + + +void PICComponent::programReload() +{ + delete m_pGpsim; + m_pGpsim = 0L; + + initPIC(true); + + slotUpdateBtns(); +} + + +void PICComponent::slotUpdateBtns() +{ + // We can get called by the destruction of gpsim after our canvas has been set to NULL + if (!canvas()) + return; + + button("run")->setEnabled( m_pGpsim && !m_pGpsim->isRunning() ); + button("pause")->setEnabled( m_pGpsim && m_pGpsim->isRunning() ); + button("reset")->setEnabled( m_pGpsim ); + button("reload")->setEnabled( !m_bLoadingProgram && (dataString("program") != _def_PICComponent_fileName) ); + + canvas()->setChanged( button("run")->boundingRect() ); + canvas()->setChanged( button("pause")->boundingRect() ); + canvas()->setChanged( button("reset")->boundingRect() ); + canvas()->setChanged( button("reload")->boundingRect() ); +} + + +#include "piccomponent.moc" + +#endif diff --git a/src/electronics/components/piccomponent.h b/src/electronics/components/piccomponent.h new file mode 100644 index 0000000..165fbf6 --- /dev/null +++ b/src/electronics/components/piccomponent.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef PICCOMPONENT_H +#define PICCOMPONENT_H + +#include "config.h" +#ifndef NO_GPSIM + +#include "component.h" + +#include +#include + +class Document; +class ECNode; +class GpsimProcessor; +class IOPIN; +class KTechlab; +class MicroInfo; +class MicroPackage; +class PIC_IOPORT; +class PICComponent; +class PICComponentPin; +class PicPin; +class TextDocument; + +typedef QMap< int, PICComponentPin * > PICComponentPinMap; + +/** +@short Electronic PIC device +@author David Saxton +*/ +class PICComponent : public Component +{ + Q_OBJECT + public: + PICComponent( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + ~PICComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual bool mouseDoubleClickEvent( const EventInfo &eventInfo ); + + void programReload(); + /** + * Sets up the pins, text, etc for the given PIC type. If info is null, + * then a generic rectangle is displayed (used when no file has been + * loaded yet). + */ + void initPackage( MicroInfo * info ); + + public slots: + void slotUpdateFileList(); + void slotUpdateBtns(); + + protected slots: + void slotCODCreationSucceeded(); + void slotCODCreationFailed(); + + protected: + /** + * Attaches all PICComponentPins to the current instance of gpsim. + */ + void attachPICComponentPins(); + void deletePICComponentPins(); + /** + * Attempts to compile the program to a symbol file, and connects the assembly + * finish signal to loadGpsim + */ + QString createSymbolFile(); + virtual void dataChanged(); + /** + * Initializes the PIC from the options the user has selected. + */ + void initPIC( bool forceReload ); + + QGuardedPtr m_pGpsim; + QString m_picFile; ///< The input program that the user selected + QString m_symbolFile; ///< The symbol file that was generated from m_picFile + bool m_bLoadingProgram; ///< True between createSymbolFile being called and the file being created + PICComponentPinMap m_picComponentPinMap; + bool m_bCreatedInitialPackage; ///< Set true once the initial package is loaded; until then, will load a package from the lastPackage data +}; + +#endif +#endif diff --git a/src/electronics/components/piccomponentpin.cpp b/src/electronics/components/piccomponentpin.cpp new file mode 100644 index 0000000..47ef6cb --- /dev/null +++ b/src/electronics/components/piccomponentpin.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * 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 "config.h" +#ifndef NO_GPSIM + +#include "micropackage.h" +#include "piccomponent.h" +#include "piccomponentpin.h" + +#include + +PICComponentPin::PICComponentPin( PICComponent * picComponent, PicPin picPin ) + : m_id( picPin.pinID ) +{ + m_gOutHigh = 0.0; + m_gOutLow = 0.0; + m_picPin = picPin; + m_pPICComponent = picComponent; + m_pLogicOut = 0l; + m_pLogicIn = 0l; + m_pIOPIN = 0l; + m_pStimulusNode = 0l; + Zth = 0.0; + Vth = 0.0; + + switch ( picPin.type ) + { + case PicPin::type_input: + { + m_pLogicIn = picComponent->createLogicIn( picComponent->ecNodeWithID(picPin.pinID) ); + break; + } + case PicPin::type_bidir: + { + m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false ); + m_gOutHigh = 0.004; + m_gOutLow = 0.004; + break; + } + case PicPin::type_open: + { + m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false ); + m_pLogicOut->setOutputHighVoltage(0.0); + m_pLogicOut->setOutputHighConductance(0.0); + m_gOutHigh = 0.0; + m_gOutLow = 0.004; + break; + } + case PicPin::type_vss: + case PicPin::type_vdd: + case PicPin::type_mclr: + case PicPin::type_osc: + default: + break; + } + + if (m_pLogicIn) + m_pLogicIn->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) ); + if (m_pLogicOut) + m_pLogicOut->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) ); +} + + +PICComponentPin::~PICComponentPin() +{ + delete m_pStimulusNode; +} + + +void PICComponentPin::attach( IOPIN * iopin ) +{ + if (!iopin) + { + kdWarning() << k_funcinfo << " iopin is NULL" << endl; + return; + } + + if (m_pStimulusNode) + { + kdWarning() << k_funcinfo << " Already have a node stimulus" << endl; + return; + } + + if (m_pIOPIN) + { + kdWarning() << k_funcinfo << " Already have an iopin" << endl; + return; + } + + m_pIOPIN = iopin; + m_pStimulusNode = new Stimulus_Node(m_id.ascii()); + m_pStimulusNode->attach_stimulus(iopin); + m_pStimulusNode->attach_stimulus(this); + + + // We need to tell the iopin whether or not we are high + if (m_pLogicOut) + logicCallback( m_pLogicOut->isHigh() ); + else if (m_pLogicIn) + logicCallback( m_pLogicIn->isHigh() ); +} + + +double PICComponentPin::get_Vth( ) +{ + if (!m_pIOPIN) + return 0.0; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + return Vth; + else + return m_pIOPIN->get_Vth(); +} + + +void PICComponentPin::set_nodeVoltage( double v ) +{ + Q_UNUSED(v); + + if ( !m_pLogicOut || !m_pIOPIN ) + return; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + { + m_pLogicOut->setOutputHighConductance(0.0); + m_pLogicOut->setOutputLowConductance(0.0); + return; + } + + m_pLogicOut->setHigh( m_pIOPIN->getDrivingState() ); + m_pLogicOut->setOutputHighConductance(m_gOutHigh); + m_pLogicOut->setOutputLowConductance(m_gOutLow); +} + + +void PICComponentPin::logicCallback( bool state ) +{ + if (!m_pIOPIN) + return; + + Vth = state ? 5e10 : 0; + bDrivingState = state; + + if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT ) + { + Zth = 1e5; + + m_pIOPIN->setDrivenState(state); + if (m_pStimulusNode) + m_pStimulusNode->update(); + } + else + Zth = 0; +} + + +void PICComponentPin::resetOutput() +{ + if ( m_pLogicOut ) + m_pLogicOut->setHigh( false ); +} + +#endif + diff --git a/src/electronics/components/piccomponentpin.h b/src/electronics/components/piccomponentpin.h new file mode 100644 index 0000000..0fc433d --- /dev/null +++ b/src/electronics/components/piccomponentpin.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef PICCOMPONENTPIN_H +#define PICCOMPONENTPIN_H + +#include "config.h" +#ifndef NO_GPSIM + +#include "logic.h" +#include "gpsim/stimuli.h" + +#include + +/** +@short Controls a pin on the PIC component +@author David Saxton + */ +class PICComponentPin : public CallbackClass, public stimulus +{ + public: + PICComponentPin( PICComponent * picComponent, PicPin picPin ); + ~PICComponentPin(); + /** + * Attach this to gpsim + */ + void attach( IOPIN * iopin ); + /** + * Called when the IOPIN this class is associated with changes state. + * Updates the associated LogicOut / LogicIn / etc according to what + * type of pin this is. + */ + virtual void set_nodeVoltage( double v ); + /** + * Called from our logic pin when the logic changes state. + */ + void logicCallback( bool state ); + /** + * Sets the output (if has one) to low. Called when the user stops the + * PIC. + */ + void resetOutput(); + + virtual double get_Vth(); + + protected: + // Conductance of pin in different configurations + double m_gOutHigh; + double m_gOutLow; + + PicPin m_picPin; + IOPIN * m_pIOPIN; + LogicOut * m_pLogicOut; + LogicIn * m_pLogicIn; + PICComponent * m_pPICComponent; + Stimulus_Node * m_pStimulusNode; + const QString m_id; +}; + +#endif +#endif diff --git a/src/electronics/components/probe.cpp b/src/electronics/components/probe.cpp new file mode 100644 index 0000000..db6725e --- /dev/null +++ b/src/electronics/components/probe.cpp @@ -0,0 +1,291 @@ +/*************************************************************************** + * 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 "ecnode.h" +#include "libraryitem.h" +#include "logic.h" +#include "pin.h" +#include "probe.h" //HACK: This has to be included before the oscilloscope headers +#include "oscilloscope.h" +#include "oscilloscopedata.h" +#include "simulator.h" +#include "voltagesource.h" + +#include +#include + +//BEGIN class Probe +Probe::Probe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ) +{ + p_probeData = 0l; + setSize( -16, -8, 32, 16 ); + + createProperty( "color", Variant::Type::Color ); + property("color")->setCaption( i18n("Color") ); + property("color")->setValue( Qt::black ); +} + + +Probe::~ Probe() +{ + delete p_probeData; +} + + +void Probe::dataChanged() +{ + m_color = dataColor("color"); + if (p_probeData) + p_probeData->setColor(m_color); + setChanged(); +} +//END class Probe + + + +//BEGIN class FloatingProbe +FloatingProbe::FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Probe( icnDocument, newItem, id ) +{ + p_probeData = m_pFloatingProbeData = static_cast(registerProbe(this)); + property("color")->setValue( p_probeData->color() ); + + createProperty( "scaling", Variant::Type::Select ); + property("scaling")->setCaption( i18n("Scaling") ); + property("scaling")->setAllowed( QStringList::split( ',', "Linear,Logarithmic") ); + property("scaling")->setValue("Linear"); + property("scaling")->setAdvanced( true ); + + createProperty( "upper_abs_value", Variant::Type::Double ); + property("upper_abs_value")->setCaption( i18n("Upper Absolute Value") ); + property("upper_abs_value")->setValue(10.0); + property("upper_abs_value")->setMinValue(0.0); + property("upper_abs_value")->setUnit("V"); + property("upper_abs_value")->setAdvanced(true); + + createProperty( "lower_abs_value", Variant::Type::Double ); + property("lower_abs_value")->setCaption( i18n("Lower Absolute Value") ); + property("lower_abs_value")->setValue(0.1); + property("lower_abs_value")->setMinValue(0.0); + property("lower_abs_value")->setUnit("V"); + property("lower_abs_value")->setAdvanced(true); +} + + +FloatingProbe::~FloatingProbe() +{ +} + + +void FloatingProbe::dataChanged() +{ + Probe::dataChanged(); + + if ( dataString("scaling") == "Linear" ) + m_pFloatingProbeData->setScaling( FloatingProbeData::Linear ); + else + m_pFloatingProbeData->setScaling( FloatingProbeData::Logarithmic ); + + m_pFloatingProbeData->setUpperAbsValue( dataDouble("upper_abs_value") ); + m_pFloatingProbeData->setLowerAbsValue( dataDouble("lower_abs_value") ); +} + + +void FloatingProbe::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x())-16; + int _y = int(y())-8; + + p.drawRect( _x, _y, 32, 16 ); + + QPointArray bezier(4); + + bezier[0] = QPoint( _x+4, _y+10 ); + bezier[1] = QPoint( _x+12, _y-6 ); + bezier[2] = QPoint( _x+20, _y+24 ); + bezier[3] = QPoint( _x+28, _y+4 ); + + p.setPen( QPen( m_color, 2 ) ); + p.drawCubicBezier(bezier); + + deinitPainter(p); +} +//END class FloatingProbe + + + +//BEGIN class VoltageProbe +Item* VoltageProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new VoltageProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* VoltageProbe::libraryItem() +{ + return new LibraryItem( + "ec/voltageprobe", + i18n("Voltage Probe"), + i18n("Outputs"), + "floatingprobe.png", + LibraryItem::lit_component, + VoltageProbe::construct ); +} + +VoltageProbe::VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : FloatingProbe( icnDocument, newItem, id ? id : "voltageprobe" ) +{ + m_name = i18n("Voltage Probe"); + m_desc = i18n("Displays the voltage at the probe point on the oscilloscope."); + + init1PinLeft(); + init1PinRight(); + m_pPin1 = m_pNNode[0]->pin(); + m_pPin2 = m_pPNode[0]->pin(); +} + + +VoltageProbe::~VoltageProbe() +{ +} + + +void VoltageProbe::stepNonLogic() +{ + m_pFloatingProbeData->addDataPoint( m_pPin1->voltage() - m_pPin2->voltage() ); +} +//END class VoltageProbe + + + +//BEGIN class CurrentProbe +Item* CurrentProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new CurrentProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* CurrentProbe::libraryItem() +{ + return new LibraryItem( + "ec/currentprobe", + i18n("Current Probe"), + i18n("Outputs"), + "floatingprobe.png", + LibraryItem::lit_component, + CurrentProbe::construct ); +} + +CurrentProbe::CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : FloatingProbe( icnDocument, newItem, id ? id : "currentprobe" ) +{ + m_name = i18n("Current Probe"); + m_desc = i18n("Displays the current at the probe point on the oscilloscope."); + + + init1PinLeft(0); + init1PinRight(0); + + m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. ); +} + + +CurrentProbe::~CurrentProbe() +{ +} + + +void CurrentProbe::stepNonLogic() +{ + m_pFloatingProbeData->addDataPoint( -m_voltageSource->cbranchCurrent(0) ); +} +//END class CurrentProbe + + + + +//BEGIN class LogicProbe +Item* LogicProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new LogicProbe( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* LogicProbe::libraryItem() +{ + QStringList ids; + ids << "ec/probe" << "ec/logicprobe"; + return new LibraryItem( + ids, + i18n("Logic Probe"), + i18n("Outputs"), + "logicprobe.png", + LibraryItem::lit_component, + LogicProbe::construct ); +} + +LogicProbe::LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id ) + : Probe( icnDocument, newItem, id ? id : "probe" ) +{ + m_name = i18n("Logic Probe"); + m_desc = i18n("Connect this probe the the point in the circuit to measure the logic value. The output will be displayed in the Oscilloscope view."); + + init1PinRight(); + m_pIn = createLogicIn( m_pPNode[0] ); + + p_probeData = p_logicProbeData = static_cast(registerProbe(this)); + property("color")->setValue( p_probeData->color() ); + + m_pSimulator = Simulator::self(); + m_pIn->setCallback( this, (CallbackPtr)(&LogicProbe::logicCallback) ); + logicCallback(false); +} + + +LogicProbe::~LogicProbe() +{ +} + + +void LogicProbe::logicCallback( bool value ) +{ + p_logicProbeData->addDataPoint( LogicDataPoint( value, m_pSimulator->time() ) ); +} + + +void LogicProbe::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = int(x())-16; + int _y = int(y())-8; + + p.drawRect( _x, _y, 32, 16 ); + + p.setPen( QPen( m_color, 2 ) ); + + p.drawLine( _x+4, _y+11, _x+6, _y+11 ); + p.drawLine( _x+6, _y+11, _x+6, _y+4 ); + p.drawLine( _x+6, _y+4, _x+10, _y+4 ); + p.drawLine( _x+10, _y+4, _x+10, _y+11 ); + p.drawLine( _x+10, _y+11, _x+16, _y+11 ); + p.drawLine( _x+16, _y+11, _x+16, _y+4 ); + p.drawLine( _x+16, _y+4, _x+23, _y+4 ); + p.drawLine( _x+23, _y+4, _x+23, _y+11 ); + p.drawLine( _x+23, _y+11, _x+28, _y+11 ); +// p.drawLine( _x+23, _y+11, _x+26, _y+11 ); +// p.drawLine( _x+26, _y+11, _x+26, _y+4 ); +// p.drawLine( _x+26, _y+4, _x+28, _y+4 ); + + deinitPainter(p); +} +//END class LogicProbe + + diff --git a/src/electronics/components/probe.h b/src/electronics/components/probe.h new file mode 100644 index 0000000..9beb62e --- /dev/null +++ b/src/electronics/components/probe.h @@ -0,0 +1,113 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef PROBE_H +#define PROBE_H + +#include + +class LogicProbeData; +class ProbeData; +class FloatingProbeData; + +/** +@author David Saxton +*/ +class Probe : public Component +{ + public: + Probe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Probe(); + + protected: + virtual void dataChanged(); + + ProbeData * p_probeData; // As obtained via registering with the oscilloscope + QColor m_color; +}; + +/** +@author David Saxton + */ +class FloatingProbe : public Probe +{ + public: + FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~FloatingProbe(); + + virtual bool doesStepNonLogic() const { return true; } + + protected: + virtual void dataChanged(); + virtual void drawShape( QPainter &p ); + + FloatingProbeData * m_pFloatingProbeData; +}; + +/** +@author David Saxton + */ +class VoltageProbe : public FloatingProbe +{ + public: + VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~VoltageProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + + protected: + Pin * m_pPin1; + Pin * m_pPin2; +}; + +/** +@author David Saxton + */ +class CurrentProbe : public FloatingProbe +{ + public: + CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~CurrentProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void stepNonLogic(); + + protected: + VoltageSource *m_voltageSource; +}; + +/** +@author David Saxton + */ +class LogicProbe : public CallbackClass, public Probe +{ + public: + LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~LogicProbe(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + void logicCallback( bool value ); + + protected: + virtual void drawShape( QPainter &p ); + + LogicProbeData * p_logicProbeData; + LogicIn * m_pIn; + Simulator * m_pSimulator; +}; + +#endif diff --git a/src/electronics/components/pushswitch.cpp b/src/electronics/components/pushswitch.cpp new file mode 100644 index 0000000..b7b38b7 --- /dev/null +++ b/src/electronics/components/pushswitch.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** + * 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 "canvasitemparts.h" +#include "libraryitem.h" +#include "pushswitch.h" +#include "switch.h" + +#include +#include +#include +#include +#include + +//BEGIN class ECPTBSwitch +Item* ECPTBSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPTBSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPTBSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/ptb_switch"), + i18n("Push-to-Break"), + i18n("Switches"), + "ptb.png", + LibraryItem::lit_component, + ECPTBSwitch::construct ); +} + +ECPTBSwitch::ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ptb_switch" ) +{ + m_name = i18n("Push to Break"); + setSize( -16, -16, 32, 24 ); + + addButton( "button", QRect( -16, 8, 32, 20 ), "" ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption( i18n("Bounce") ); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption( i18n("Bounce Period") ); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft(0); + init1PinRight(0); + + m_switch = createSwitch( m_pPNode[0], m_pNNode[0], false ); + pressed = false; +} + +ECPTBSwitch::~ECPTBSwitch() +{ +} + + +void ECPTBSwitch::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECPTBSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + const int _height = height()-8; + + int dy = pressed ? 6 : 4; + + p.drawLine( _x+width()/4, _y+dy, _x+(3*width())/4, _y+dy ); // Top horizontal line + p.drawLine( _x, _y+(_height/2)-radius+dy, _x+width(), _y+(_height/2)-radius+dy ); // Bottom horizontal line + p.drawLine( _x+width()/2, _y+dy, _x+width()/2, _y+(_height/2)-radius+dy ); // Vertical line + + p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle + p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle + + deinitPainter(p); +} + +void ECPTBSwitch::buttonStateChanged( const QString &id, bool state ) +{ + if ( id != "button" ) + return; + m_switch->setState( state ? Switch::Open : Switch::Closed ); + pressed = state; +} +//END class ECPTBSwitch + + +//BEGIN class ECPTMSwitch +Item* ECPTMSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECPTMSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECPTMSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/ptm_switch"), + i18n("Push-to-Make"), + i18n("Switches"), + "ptm.png", + LibraryItem::lit_component, + ECPTMSwitch::construct ); +} + +ECPTMSwitch::ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "ptm_switch" ) +{ + m_name = i18n("Push to Make"); + setSize( -16, -16, 32, 24 ); + + addButton( "button", QRect( -16, 8, 32, 20 ), "" ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft(0); + init1PinRight(0); + + m_switch = createSwitch( m_pPNode[0], m_pNNode[0], true ); + pressed = false; +} + + +ECPTMSwitch::~ECPTMSwitch() +{ +} + + +void ECPTMSwitch::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECPTMSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + const int _height = height()-8; + + int dy = pressed ? 1 : 3; + + p.drawLine( _x+width()/4, _y-dy, _x+(3*width())/4, _y-dy ); // Top horizontal line + p.drawLine( _x, _y+(_height/2)-radius-dy, _x+width(), _y+(_height/2)-radius-dy ); // Bottom horizontal line + p.drawLine( _x+width()/2, _y-dy, _x+width()/2, _y+(_height/2)-radius-dy ); // Vertical line + + p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle + p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle + + deinitPainter(p); +} + +void ECPTMSwitch::buttonStateChanged( const QString &id, bool state ) +{ + if ( id != "button" ) return; + m_switch->setState( state ? Switch::Closed : Switch::Open ); + pressed = state; +} +//END class ECPTMSwitch + diff --git a/src/electronics/components/pushswitch.h b/src/electronics/components/pushswitch.h new file mode 100644 index 0000000..c22ea93 --- /dev/null +++ b/src/electronics/components/pushswitch.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef PUSHSWITCH_H +#define PUSHSWITCH_H + +#include "component.h" + +/** +@short Push-to-Break switch component +@author David Saxton +*/ +class ECPTBSwitch : public Component +{ +public: + ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPTBSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + + +/** +@short Push-to-make switch +@author David Saxton +*/ +class ECPTMSwitch : public Component +{ +public: + ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECPTMSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + + +#endif diff --git a/src/electronics/components/ram.cpp b/src/electronics/components/ram.cpp new file mode 100644 index 0000000..add745a --- /dev/null +++ b/src/electronics/components/ram.cpp @@ -0,0 +1,232 @@ +/*************************************************************************** + * 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 "libraryitem.h" +#include "logic.h" +#include "ram.h" +#include "variant.h" + +#include +#include + +Item* RAM::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new RAM( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* RAM::libraryItem() +{ + return new LibraryItem( + QString("ec/ram"), + i18n("RAM"), + i18n("Integrated Circuits"), + "ic2.png", + LibraryItem::lit_component, + RAM::construct + ); +} + +RAM::RAM( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "ram" ) +{ + m_name = i18n("RAM"); + m_desc = i18n("This RAM stores data as a collection of words; each of which contains word size bits of data.

To read data, set the CS (chip select) and the OE (output enable) pins high, and select the word using the address pins A*. The word is outputted on the data-out pins: DO*.

To write data, set the CS (chip select) and the WE (write enable) pins high, and select the address to write to with the A* pins. Write to the selected word using the data-in pins: DI*.

The Address Size is the number of bits that determine an address; so the total number of words stored will be 2^Address Size."); + + m_data = 0l; + m_pCS = 0l; + m_pOE = 0l; + m_pWE = 0l; + m_wordSize = 0; + m_addressSize = 0; + + createProperty( "wordSize", Variant::Type::Int ); + property("wordSize")->setCaption( i18n("Word Size") ); + property("wordSize")->setMinValue(1); + property("wordSize")->setMaxValue(256); + property("wordSize")->setValue(2); + + createProperty( "addressSize", Variant::Type::Int ); + property("addressSize")->setCaption( i18n("Address Size") ); + property("addressSize")->setMinValue(1); + property("addressSize")->setMaxValue(32); + property("addressSize")->setValue(4); + + m_data = createProperty( "data", Variant::Type::Raw )->value().asBitArray(); +} + +RAM::~RAM() +{ +} + + +void RAM::dataChanged() +{ + m_wordSize = dataInt("wordSize"); + m_addressSize = dataInt("addressSize"); + + int newSize = int( m_wordSize * std::pow( 2., m_addressSize ) ); + m_data.resize(newSize); + + initPins(); +} + + +void RAM::inStateChanged( bool newState ) +{ + Q_UNUSED(newState); + + bool cs = m_pCS->isHigh(); + bool oe = m_pOE->isHigh(); + bool we = m_pWE->isHigh(); + + if ( !cs || !oe ) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh(false); + } + + if ( !cs || (!oe && !we) ) + return; + + unsigned address = 0; + for ( int i = 0; i < m_addressSize; ++i ) + address += (m_address[i]->isHigh() ? 1 : 0) << i; + + if (we) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_data[ m_wordSize * address + i ] = m_dataIn[i]->isHigh(); + } + + if (oe) + { + for ( int i = 0; i < m_wordSize; ++i ) + m_dataOut[i]->setHigh( m_data[ m_wordSize * address + i ] ); + } +} + + +void RAM::initPins() +{ + int oldWordSize = m_dataIn.size(); + int oldAddressSize = m_address.size(); + + int newWordSize = dataInt("wordSize"); + int newAddressSize = dataInt("addressSize"); + + if ( newAddressSize == oldAddressSize && + newWordSize == oldWordSize ) + return; + + QStringList leftPins; // Pins on left of IC + leftPins << "CS" << "OE" << "WE"; + for ( int i = 0; i < newAddressSize; ++i ) + leftPins << QString("A%1").arg( QString::number(i) ); + + QStringList rightPins; // Pins on right of IC + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DI%1").arg( QString::number(i-1) ); + for ( unsigned i = newWordSize; i > 0; --i ) + rightPins << QString("DO%1").arg( QString::number(i-1) ); + + // Make pin lists of consistent sizes + for ( unsigned i = leftPins.size(); i < rightPins.size(); ++i ) + leftPins.append(""); + for ( unsigned i = rightPins.size(); i < leftPins.size(); ++i ) + rightPins.prepend(""); + + QStringList pins = leftPins + rightPins; + + initDIPSymbol( pins, 72 ); + initDIP(pins); + + ECNode *node; + + if (!m_pCS) + { + node = ecNodeWithID("CS"); + m_pCS = createLogicIn(node); + m_pCS->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pOE) + { + node = ecNodeWithID("OE"); + m_pOE = createLogicIn(node); + m_pOE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if (!m_pWE) + { + node = ecNodeWithID("WE"); + m_pWE = createLogicIn(node); + m_pWE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + + if ( newWordSize > oldWordSize ) + { + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + + for ( int i = oldWordSize; i < newWordSize; ++i ) + { + node = ecNodeWithID( QString("DI%1").arg( QString::number(i) ) ); + m_dataIn.insert( i, createLogicIn(node) ); + m_dataIn[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + + node = ecNodeWithID( QString("DO%1").arg( QString::number(i) ) ); + m_dataOut.insert( i, createLogicOut(node, false) ); + } + } + else if ( newWordSize < oldWordSize ) + { + for ( int i = newWordSize; i < oldWordSize; ++i ) + { + QString id = QString("DO%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataIn[i], false ); + removeNode(id); + + id = QString("DI%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_dataOut[i], false ); + removeNode(id); + } + + m_dataIn.resize(newWordSize); + m_dataOut.resize(newWordSize); + } + + if ( newAddressSize > oldAddressSize ) + { + m_address.resize(newAddressSize); + + for ( int i = oldAddressSize; i < newAddressSize; ++i ) + { + node = ecNodeWithID( QString("A%1").arg( QString::number(i) ) ); + m_address.insert( i, createLogicIn(node) ); + m_address[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) ); + } + } + else if ( newAddressSize < oldAddressSize ) + { + for ( int i = newAddressSize; i < oldAddressSize; ++i ) + { + QString id = QString("A%1").arg( QString::number(i) ); + removeDisplayText(id); + removeElement( m_address[i], false ); + removeNode(id); + } + + m_address.resize(newAddressSize); + } +} + + diff --git a/src/electronics/components/ram.h b/src/electronics/components/ram.h new file mode 100644 index 0000000..7b78ee9 --- /dev/null +++ b/src/electronics/components/ram.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef RAM_H +#define RAM_H + +#include "component.h" +#include "logic.h" + +#include +#include + +/** +@author David Saxton +*/ +class RAM : public CallbackClass, public Component +{ + public: + RAM( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~RAM(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + protected: + void initPins(); + virtual void dataChanged(); + void inStateChanged( bool newState ); + + QBitArray m_data; + LogicIn * m_pCS; // Chip select + LogicIn * m_pOE; // Output enable + LogicIn * m_pWE; // Write enable + + int m_wordSize; + int m_addressSize; + + QPtrVector m_address; + QPtrVector m_dataIn; + QPtrVector m_dataOut; +}; + +#endif diff --git a/src/electronics/components/resistordip.cpp b/src/electronics/components/resistordip.cpp new file mode 100644 index 0000000..d2c5bdb --- /dev/null +++ b/src/electronics/components/resistordip.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * 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 "libraryitem.h" +#include "node.h" +#include "resistance.h" +#include "resistordip.h" + +#include +#include +#include + +Item* ResistorDIP::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ResistorDIP( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ResistorDIP::libraryItem() +{ + return new LibraryItem( + "ec/resistordip", + i18n("Resistor DIP"), + i18n("Discrete"), + "resistordip.png", + LibraryItem::lit_component, + ResistorDIP::construct + ); +} + +ResistorDIP::ResistorDIP( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "multiplexer" ) +{ + m_name = i18n("Resistor DIP"); + m_desc = i18n("Set of resistors with identical values in a Dual Inline Package."); + + m_resistorCount = 0; + for ( int i=0; isetCaption( i18n("Resistance") ); + property("resistance")->setUnit( QChar(0x3a9) ); + property("resistance")->setValue(1e4); + property("resistance")->setMinValue(1e-6); + + createProperty( "count", Variant::Type::Int ); + property("count")->setCaption( i18n("Count") ); + property("count")->setMinValue(2); + property("count")->setMaxValue(maxCount); + property("count")->setValue(8); +} + +ResistorDIP::~ResistorDIP() +{ +} + + +void ResistorDIP::dataChanged() +{ + initPins(); + const double resistance = dataDouble("resistance"); + for ( int i=0; isetResistance(resistance); + + const QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9); + addDisplayText( "res", QRect( offsetX(), offsetY()-16, 32, 12 ), display ); +} + + +void ResistorDIP::initPins() +{ + const int count = dataInt("count"); + const double resistance = dataDouble("resistance"); + + if ( count == m_resistorCount ) + return; + + if ( count < m_resistorCount ) + { + for ( int i=count; i +#include +#include +#include + +#include + +//BEGIN class ECRotoSwitch +Item* ECRotoSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECRotoSwitch( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECRotoSwitch::libraryItem() +{ + return new LibraryItem( + QString("ec/roto_switch"), + i18n("Rotary"), + i18n("Switches"), + "rotary.png", + LibraryItem::lit_component, + ECRotoSwitch::construct ); +} + + +ECRotoSwitch::ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id ) +: Component( icnDocument, newItem, id ? id : "roto_switch" ), +m_numPositions(0) +{ +// m_name = i18n("Rotary Switch(WIP)"); + m_name = i18n("Rotary Switch"); + m_desc = i18n("Rotary Switch"); ///< \todo better description for rotoswitch + QPointArray pa; + pa.makeArc( -_pinInnerRadius, -_pinInnerRadius, 2*_pinInnerRadius, 2*_pinInnerRadius , 0, 16*360 ); + setItemPoints( pa ); + //setSize( -64, -64, 128, 128 ); + + //half the side length of the buttons + int buttonRadius = 10; + addButton( "go_left", QRect( -_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), "<", false ); + addButton( "go_right", QRect(_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), ">", false ); + + /*Variant * v = createProperty( "button_map", Variant::Type::String ); + v->setCaption( i18n("Button Map") ); + v->setAdvanced(true); + const QString defButtonMap("SSSSSSSSSSSM"); + v->setValue(defButtonMap); + */ + Variant * v = createProperty( "num_positions", Variant::Type::Int ); + v->setCaption( i18n("Number of Positions") ); + v->setAdvanced(false); + v->setValue(6); + v->setMinValue(3); + m_inNode = createPin(0,height()/2,270,"in"); + + v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + + v = createProperty( "cur_position", Variant::Type::Int ); + v->setHidden( true ); + v->setValue( 0 ); + + //v = createProperty( "left_momentary", Variant::Type::Bool ); + //v->setCaption(i18n("Left Momentary" ) ); + //v->setValue(false); +} + + +ECRotoSwitch::~ECRotoSwitch() +{ +} + + +void ECRotoSwitch::dataChanged() +{ + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_curPosition = dataInt( "cur_position" ); + setUpSwitches(); + if(m_positions[m_curPosition].posSwitch->state() != Switch::Closed) + { + m_positions[m_curPosition].posSwitch->setState(Switch::Closed); + } + for(int i = 0; i < m_numPositions; i++) + { + m_positions[i].posSwitch->setBounce( bounce, bouncePeriod_ms ); + } +} + +inline int roundTo10(int a){return ((a/10)+(a%10<5?0:1))*10;} +void ECRotoSwitch::drawShape( QPainter &p ) +{ + initPainter(p); + + + int cx = static_cast(x()); + int cy = static_cast(y()); + + const int rotorRadius = 5; + + + //draw the rotor + p.drawEllipse(cx - rotorRadius, cy-rotorRadius, 2*rotorRadius, 2*rotorRadius); + //and its connection + p.drawLine(cx, cy+rotorRadius, cx, cy+_pinInnerRadius); + + //draw the output positions + double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1); + //kdDebug() << "drawShape: " << bigRadius << " " << angleBetweenPositions << endl; + + /// \internal \brief Round to the nearest multiple of 8 +#define round_8(a) (((a) > 0) ? int(((a)+4)/8)*8 : int(((a)-4)/8)*8) + for(int i = 0; i < m_numPositions ; i++) + { + double angle = (7*M_PI/6) - (i * angleBetweenPositions); + int contactX = static_cast(_contactRingRadius * cos(angle)); + int contactY = static_cast(_contactRingRadius * sin(angle)); + + p.drawEllipse(cx+contactX-_contactRadius, cy-contactY-_contactRadius, 2*_contactRadius, 2*_contactRadius); + int pinX, pinY; + switch(m_positions[i].pinAngle) + { + case 180: + pinX = _pinInnerRadius; + pinY = round_8(contactY); + break; + case 90: + pinX = round_8(contactX); + pinY = _pinInnerRadius; + break; + case 0: + pinX = -_pinInnerRadius; + pinY = round_8(contactY); + break; + default: + assert(!"Bad pin angle"); + } + p.drawLine(cx+contactX, cy-contactY, cx+pinX, cy-pinY); + //kdDebug() << contactX <<", "<< contactY <(_contactRingRadius * cos(angle)); + int contactY = static_cast(_contactRingRadius * sin(angle)); + int rotorX = static_cast(rotorRadius * cos(angle)); + int rotorY = static_cast(rotorRadius * sin(angle)); + p.drawLine(cx+rotorX, cy-rotorY, cx+contactX, cy-contactY); + + + deinitPainter(p); +} + +void ECRotoSwitch::buttonStateChanged( const QString & id, bool state ) +{ + SwitchPosition& curSP = m_positions[m_curPosition]; + int nextPos = m_curPosition; + if(m_numPositions < 2) + { + return; + } + if(!state) //release + { + if(!curSP.isMomentary) + { + return; + } + + if(m_curPosition == 0) + { + nextPos = m_curPosition + 1; + } + else if(m_curPosition == m_numPositions - 1) + { + nextPos = m_curPosition - 1; + } + + } + else //press + { + if(id == "go_left" && m_curPosition > 0) + { + nextPos = m_curPosition - 1; + } + else if(id == "go_right" && m_curPosition < m_numPositions - 1) + { + nextPos = m_curPosition + 1; + } + + } + if(nextPos != m_curPosition) + { + SwitchPosition& nextSP = m_positions[nextPos]; + + curSP.posSwitch->setState(Switch::Open); + nextSP.posSwitch->setState(Switch::Closed); + + m_curPosition = nextPos; + + property( "cur_position" )->setValue( m_curPosition ); + } +} + + +/*! + Set up the switches according to the button_map + * + * + */ +void ECRotoSwitch::setUpSwitches() +{ + if( dataInt("num_positions") == m_numPositions ) + { + // number of positions didn't change, so we don't have to do anything. + return; + } + //this uses the _old_ value of m_numPositions! + for(int i=0; i= m_numPositions ) + { + setActivePosition( m_numPositions - 1 ); + } + m_positions.clear();///\todo readjust old pins + m_positions.reserve(m_numPositions); + double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1); + //kdDebug() << "setUpSwitches: " << bigRadius << " " << angleBetweenPositions << endl; + for( int i = 0; i < m_numPositions; i++) + { + double angle = (7*M_PI/6) - (i * angleBetweenPositions); + int contactX = static_cast(_contactRingRadius * cos(angle)); + int contactY = static_cast(_contactRingRadius * sin(angle)); + + SwitchPosition sp; + if(angle > 3*M_PI/4) + { + sp.pinAngle = 0; + contactX = -_pinOuterRadius; + } + else if(angle > M_PI/4) + { + sp.pinAngle = 90; + contactY=_pinOuterRadius; + } + else + { + sp.pinAngle = 180; + contactX = _pinOuterRadius; + } + // kdDebug() << contactX <<", "<< contactY <setState(Switch::Open); + nextSP.posSwitch->setState(Switch::Closed); + + m_curPosition = newPosition; + + property( "cur_position" )->setValue( m_curPosition ); + +} +//END class ECRotoSwitch diff --git a/src/electronics/components/rotoswitch.h b/src/electronics/components/rotoswitch.h new file mode 100644 index 0000000..909c0ea --- /dev/null +++ b/src/electronics/components/rotoswitch.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2005 by John Myers * + * electronerd@electronerdia.net * + * * + * 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. * + ***************************************************************************/ + +#ifndef ROTOSWITCH_H +#define ROTOSWITCH_H + +#include "component.h" +#include + +struct SwitchPosition +{ + ECNode* node; + Switch* posSwitch; + bool isMomentary; + int pinAngle; +}; + +/** + * A rotary switch + * \author John Myers + */ +class ECRotoSwitch : public Component +{ +public: + ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECRotoSwitch(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + +private: + virtual void drawShape( QPainter &p ); + + int m_numPositions; + int m_curPosition; + + ///Half the total width of the component including pins + static const int _pinOuterRadius = 64; + ///The width of the pins + static const int _pinWidth = 8; + ///the radius of the circle centered at the origin and tangent to the inner edge of the rows of pins + static const int _pinInnerRadius = _pinOuterRadius - _pinWidth; + ///gap between pins and contact circles + static const int _wireGap = 7; + ///The radius of the largest circle tangent to the pin circles + static const int _contactOuterRadius = _pinInnerRadius - _wireGap; + ///The radius of the circles used to show positions + static const int _contactRadius = 2; + ///The radius of the ring of positions + static const int _contactRingRadius = _contactOuterRadius - _contactRadius; + + QValueVector m_positions; + ECNode* m_inNode; + +protected: + void setUpSwitches(); +protected: + void setActivePosition(int newPosition); +}; +#endif //ROTOSWITCH_H diff --git a/src/electronics/components/serialportcomponent.cpp b/src/electronics/components/serialportcomponent.cpp new file mode 100644 index 0000000..c8e6a4e --- /dev/null +++ b/src/electronics/components/serialportcomponent.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + * 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 "port.h" +#include "serialportcomponent.h" + +#include "ecnode.h" +#include "itemdocument.h" +#include "libraryitem.h" +#include "pin.h" +#include "resistance.h" + +#include +#include +#include + +#include +#include + +Item* SerialPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new SerialPortComponent( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* SerialPortComponent::libraryItem() +{ + return new LibraryItem( + "ec/serial_port", + i18n("Serial Port"), + i18n("Connections"), + "ic1.png", + LibraryItem::lit_component, + SerialPortComponent::construct + ); +} + +SerialPortComponent::SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "serial_port" ) +{ + m_name = i18n("Serial Port"); + m_desc = i18n("Interface to a serial port. The pins are:
" + "
    " + "
  • CD - Carrier Detect (control; output)
  • " + "
  • RD - Received Data (data; output)
  • " + "
  • TD - Transmitted Data (data; input)
  • " + "
  • DTR - Data Terminal Ready (control; input)
  • " + "
  • GND - Signal Ground (ground)
  • " + "
  • DSR - Data Set Ready (control; input)
  • " + "
  • RTS - Request to Send (control; input)
  • " + "
  • CTS - Clear to Send (control; output)
  • " + "
  • RI - Ring Indicator (control; output)
  • " + "
"); + + QPointArray pa( 4 ); + pa[0] = QPoint( -32, -48 ); + pa[1] = QPoint( 32, -40 ); + pa[2] = QPoint( 32, 40 ); + pa[3] = QPoint( -32, 48 ); + + setItemPoints( pa ); + + m_pSerialPort = new SerialPort(); + + ECNode * pin = 0; + + // Works + pin = createPin( -40, 32, 0, "CD" ); + addDisplayText( "CD", QRect( -28, 24, 28, 16 ), "CD", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pCD = createLogicOut( pin, false ); + + // Doesn't work +// pin = createPin( -40, 16, 0, "RD" ); + addDisplayText( "RD", QRect( -28, 8, 28, 16 ), "RD", true, Qt::AlignLeft | Qt::AlignVCenter ); +// m_pRD = createLogicOut( pin, false ); + + // Works + pin = createPin( -40, 0, 0, "TD" ); + addDisplayText( "TD", QRect( -28, -8, 28, 16 ), "TD", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pTD = createLogicIn( pin); + m_pTD->setCallback( this, (CallbackPtr)(&SerialPortComponent::tdCallback) ); + + // Works + pin = createPin( -40, -16, 0, "DTR" ); + addDisplayText( "DTR", QRect( -28, -24, 28, 16 ), "DTR", true, Qt::AlignLeft | Qt::AlignVCenter ); + m_pDTR = createLogicIn( pin ); + m_pDTR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dtrCallback) ); + + // N/A + pin = createPin( -40, -32, 0, "GND" ); + addDisplayText( "GND", QRect( -28, -40, 28, 16 ), "GND", true, Qt::AlignLeft | Qt::AlignVCenter ); + pin->pin()->setGroundType( Pin::gt_always ); + + // Doesn't work +// pin = createPin( 40, 24, 180, "DSR" ); + addDisplayText( "DSR", QRect( 0, 16, 28, 16 ), "DSR", true, Qt::AlignRight | Qt::AlignVCenter ); +// m_pDSR = createLogicIn( pin ); +// m_pDSR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dsrCallback) ); + + // Doesn't work +// pin = createPin( 40, 8, 180, "RTS" ); + addDisplayText( "RTS", QRect( 0, 0, 28, 16 ), "RTS", true, Qt::AlignRight | Qt::AlignVCenter ); +// m_pRTS = createLogicIn( pin ); +// m_pRTS->setCallback( this, (CallbackPtr)(&SerialPortComponent::rtsCallback) ); + + // Works + pin = createPin( 40, -8, 180, "CTS" ); + addDisplayText( "CTS", QRect( 0, -16, 28, 16 ), "CTS", true, Qt::AlignRight | Qt::AlignVCenter ); + m_pCTS = createLogicOut( pin, false ); + + // Works + pin = createPin( 40, -24, 180, "RI" ); + addDisplayText( "RI", QRect( 0, -32, 28, 16 ), "RI", true, Qt::AlignRight | Qt::AlignVCenter ); + m_pRI = createLogicOut( pin, false ); + + Variant * v = createProperty( "port", Variant::Type::Combo ); + v->setAllowed( SerialPort::ports( Port::ExistsAndRW ) ); + v->setCaption( i18n("Port") ); + +// v = createProperty( "baudRate", Variant::Type::Select ); +// v->setAllowed( QStringList::split( ",", "B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400" ) ); +// v->setCaption( i18n("Baud rate") ); +// v->setValue("B9600"); +} + + +SerialPortComponent::~SerialPortComponent() +{ + delete m_pSerialPort; +} + + +void SerialPortComponent::dataChanged() +{ +#if 0 + QString baudString = dataString("baudRate"); + unsigned baudRate = 0; + + if ( baudString == "B0" ) + baudRate = B0; + else if ( baudString == "B50" ) + baudRate = B50; + else if ( baudString == "B75" ) + baudRate = B75; + else if ( baudString == "B110" ) + baudRate = B110; + else if ( baudString == "B134" ) + baudRate = B134; + else if ( baudString == "B150" ) + baudRate = B150; + else if ( baudString == "B200" ) + baudRate = B200; + else if ( baudString == "B300" ) + baudRate = B300; + else if ( baudString == "B600" ) + baudRate = B600; + else if ( baudString == "B1200" ) + baudRate = B1200; + else if ( baudString == "B1800" ) + baudRate = B1800; + else if ( baudString == "B2400" ) + baudRate = B2400; + else if ( baudString == "B4800" ) + baudRate = B4800; + else if ( baudString == "B9600" ) + baudRate = B9600; + else if ( baudString == "B19200" ) + baudRate = B19200; + else if ( baudString == "B38400" ) + baudRate = B38400; + else + { + kdError() << k_funcinfo << "Unknown baud rate = \""<closePort(); + return; + } + + if ( ! m_pSerialPort->openPort( port, baudRate ) ) + { + p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) ); + return; + } +} + + +void SerialPortComponent::stepNonLogic() +{ + m_pCD->setHigh( m_pSerialPort->pinState( SerialPort::CD ) ); +// m_pRD->setHigh( m_pSerialPort->pinState( SerialPort::RD ) ); + m_pCTS->setHigh( m_pSerialPort->pinState( SerialPort::CTS ) ); + m_pRI->setHigh( m_pSerialPort->pinState( SerialPort::RI ) ); +} + + +void SerialPortComponent::tdCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::TD, isHigh ); +} + + +void SerialPortComponent::dtrCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::DTR, isHigh ); +} + + +void SerialPortComponent::dsrCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::DSR, isHigh ); +} + + +void SerialPortComponent::rtsCallback( bool isHigh ) +{ + m_pSerialPort->setPinState( SerialPort::RTS, isHigh ); +} + + +void SerialPortComponent::drawShape( QPainter & p ) +{ + drawPortShape( p ); +} diff --git a/src/electronics/components/serialportcomponent.h b/src/electronics/components/serialportcomponent.h new file mode 100644 index 0000000..4f9bc9a --- /dev/null +++ b/src/electronics/components/serialportcomponent.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef SERIALPORTCOMPONENT_H +#define SERIALPORTCOMPONENT_H + +#include "logic.h" +#include "component.h" + +class SerialPort; + +/** +@author David Saxton +*/ +class SerialPortComponent : public CallbackClass, public Component +{ + public: + SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~SerialPortComponent(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + virtual void stepNonLogic(); + virtual bool doesStepNonLogic() const { return true; } + + protected: + /** + * @param baudRate as defined in + */ + void initPort( const QString & port, unsigned baudRate ); + virtual void dataChanged(); + virtual void drawShape( QPainter & p ); + + void tdCallback( bool isHigh ); + void dtrCallback( bool isHigh ); + void dsrCallback( bool isHigh ); + void rtsCallback( bool isHigh ); + + LogicIn * m_pTD; + LogicIn * m_pDTR; +// LogicIn * m_pDSR; +// LogicIn * m_pRTS; + + LogicOut * m_pCD; +// LogicOut * m_pRD; + LogicOut * m_pCTS; + LogicOut * m_pRI; + + SerialPort * m_pSerialPort; +}; + +#endif diff --git a/src/electronics/components/toggleswitch.cpp b/src/electronics/components/toggleswitch.cpp new file mode 100644 index 0000000..4efe9ab --- /dev/null +++ b/src/electronics/components/toggleswitch.cpp @@ -0,0 +1,407 @@ +/*************************************************************************** + * 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 "toggleswitch.h" + +#include "canvasitemparts.h" +#include "ecnode.h" +#include "libraryitem.h" +#include "switch.h" + +#include +#include + +//BEGIN class ECDPDT +Item* ECDPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDPDT( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDPDT::libraryItem() +{ + return new LibraryItem( + QString("ec/dpdt_toggle"), + i18n("DPDT"), + i18n("Switches"), + "dpdt.png", + LibraryItem::lit_component, + ECDPDT::construct ); +} + + +ECDPDT::ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, id ? id : "dpdt_toggle" ) +{ + m_name = i18n("DPDT Toggle"); + m_desc = i18n("Double-Pole Double-Throw switch."); + setSize( -16, -32, 32, 64 ); + + addButton( "button", QRect( -16, 32, 32, 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init4PinRight( -24, -8, 8, 24 ); + + init2PinLeft( -16, 16 ); + + m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false ); + m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true ); + m_switch3 = createSwitch( m_pNNode[1], m_pPNode[2], false ); + m_switch4 = createSwitch( m_pNNode[1], m_pPNode[3], true ); + pressed = false; +} + + +ECDPDT::~ECDPDT() +{ +} + + +void ECDPDT::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); + m_switch3->setBounce( bounce, bouncePeriod_ms ); + m_switch4->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECDPDT::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-32; + const int radius = 2; + + p.drawEllipse( _x, _y+15, 2*radius, 2*radius ); + p.drawEllipse( _x, _y+47, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+23, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+39, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+55, 2*radius, 2*radius ); + + const int dy = pressed ? 6 : -6; + + p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+16+dy ); + p.drawLine( _x+2*radius, _y+48, _x+width()-2*radius+2, _y+48+dy ); + + deinitPainter(p); +} + +void ECDPDT::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch1->setState( state ? Switch::Open : Switch::Closed ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); + m_switch3->setState( state ? Switch::Open : Switch::Closed ); + m_switch4->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECDPDT + + +//BEGIN class ECDPST +Item* ECDPST::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECDPST( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECDPST::libraryItem() +{ + return new LibraryItem( + QString("ec/dpst_toggle"), + i18n("DPST"), + i18n("Switches"), + "dpst.png", + LibraryItem::lit_component, + ECDPST::construct ); +} + +ECDPST::ECDPST( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "dpst_toggle" ) +{ + m_name = i18n("DPST Toggle"); + m_desc = i18n("Double-Pole Single-Throw switch."); + setSize( -16, -16, 32, 32 ); + + addButton( "button", QRect( -16, 16, 32, 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init2PinLeft( -8, 8 ); + init2PinRight( -8, 8 ); + + m_switch1 = createSwitch( m_pPNode[0], m_pNNode[0], true ); + m_switch2 = createSwitch( m_pPNode[1], m_pNNode[1], true ); + pressed = false; +} + + +ECDPST::~ECDPST() +{ +} + + +void ECDPST::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECDPST::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-16; + const int radius = 2; + + p.drawEllipse( _x, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x, _y+22, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius ); + + const int dy = pressed ? 6 : 0; + + p.drawLine( _x+2*radius,_y+7,_x+width()-2*radius,_y+1+dy ); + p.drawLine( _x+2*radius,_y+24,_x+width()-2*radius,_y+18+dy ); + + deinitPainter(p); +} + +void ECDPST::buttonStateChanged( const QString &, bool state ) +{ + m_switch1->setState( state ? Switch::Closed : Switch::Open ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); + pressed = state; +} +//END class ECDPST + + +//BEGIN class ECSPDT +Item* ECSPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSPDT( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSPDT::libraryItem() +{ + return new LibraryItem( + QString("ec/spdt_toggle"), + i18n("SPDT"), + i18n("Switches"), + "spdt.png", + LibraryItem::lit_component, + ECSPDT::construct ); +} + + +ECSPDT::ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "spdt_toggle" ) +{ + m_name = i18n("SPDT Toggle"); + m_desc = i18n("Single-Pole Double-Throw switch."); + setSize( -16, -16, 32, 32 ); + + addButton( "button", QRect( -16, 16, width(), 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + init1PinLeft( 0 ); + init2PinRight( -8, 8 ); + + m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false ); + m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true ); + + pressed = false; +} + + +ECSPDT::~ECSPDT() +{ +} + + +void ECSPDT::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + + m_switch1->setBounce( bounce, bouncePeriod_ms ); + m_switch2->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECSPDT::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-16; + const int radius = 2; + + p.drawEllipse( _x, _y+15, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius ); + + const int dy = pressed ? 21 : 10; + p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+dy ); + + deinitPainter(p); +} + +void ECSPDT::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch1->setState( state ? Switch::Open : Switch::Closed ); + m_switch2->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECSPDT + + +//BEGIN class ECSPST +Item* ECSPST::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ECSPST( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ECSPST::libraryItem() +{ + return new LibraryItem( + QString("ec/spst_toggle"), + i18n("SPST"), + i18n("Switches"), + "spst.png", + LibraryItem::lit_component, + ECSPST::construct + ); +} + + +ECSPST::ECSPST( ICNDocument *icnDocument, bool newItem, const char *id ) + : Component( icnDocument, newItem, (id) ? id : "spst_toggle" ) +{ + m_name = i18n("SPST Toggle"); + m_desc = i18n("Single-Pole Single-Throw switch."); + setSize( -16, -8, 32, 16 ); + pressed = false; + + addButton( "button", QRect( -16, 8, width(), 20 ), "", true ); + + createProperty( "button_text", Variant::Type::String ); + property("button_text")->setCaption( i18n("Button Text") ); + + Variant * v = createProperty( "bounce", Variant::Type::Bool ); + v->setCaption("Bounce"); + v->setAdvanced(true); + v->setValue(false); + + v = createProperty( "bounce_period", Variant::Type::Double ); + v->setCaption("Bounce Period"); + v->setAdvanced(true); + v->setUnit("s"); + v->setValue(5e-3); + + button("button")->setState(pressed); + + init1PinLeft(); + init1PinRight(); + + m_switch = createSwitch( m_pNNode[0], m_pPNode[0], !pressed ); +} + + +ECSPST::~ECSPST() +{ +} + + +void ECSPST::dataChanged() +{ + button("button")->setText( dataString("button_text") ); + + bool bounce = dataBool("bounce"); + int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3); + m_switch->setBounce( bounce, bouncePeriod_ms ); +} + + +void ECSPST::drawShape( QPainter &p ) +{ + initPainter(p); + + int _x = (int)x()-16; + int _y = (int)y()-8; + const int radius = 2; + + p.drawEllipse( _x, _y+7, 2*radius, 2*radius ); + p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius ); + const int dy = pressed ? 0 : -6; + p.drawLine( _x+2*radius, _y+8, _x+width()-2*radius, _y+8+dy ); + + deinitPainter(p); +} + +void ECSPST::buttonStateChanged( const QString &, bool state ) +{ + pressed = state; + m_switch->setState( state ? Switch::Closed : Switch::Open ); +} +//END class ECSPST + diff --git a/src/electronics/components/toggleswitch.h b/src/electronics/components/toggleswitch.h new file mode 100644 index 0000000..80fd064 --- /dev/null +++ b/src/electronics/components/toggleswitch.h @@ -0,0 +1,116 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef TOGGLESWITCH_H +#define TOGGLESWITCH_H + +#include "component.h" + +/** +@short Double Pole Double Throw +@author David Saxton +*/ +class ECDPDT : public Component +{ +public: + ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDPDT(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + Switch *m_switch3; + Switch *m_switch4; + bool pressed; +}; + + +/** +@short Double Pole Single Throw +@author David Saxton +*/ +class ECDPST : public Component +{ +public: + ECDPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECDPST(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + bool pressed; +}; + + +/** +@short Single Pole Double Throw +@author David Saxton +*/ +class ECSPDT : public Component +{ +public: + ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSPDT(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch1; + Switch *m_switch2; + bool pressed; +}; + + +/** +@short Single-Pole Single-Throw Switch +@author David Saxton +*/ +class ECSPST : public Component +{ +public: + ECSPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ECSPST(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void buttonStateChanged( const QString &id, bool state ); + virtual void dataChanged(); + virtual bool canFlip() const { return true; } + +private: + virtual void drawShape( QPainter &p ); + Switch *m_switch; + bool pressed; +}; + +#endif diff --git a/src/electronics/ecnode.cpp b/src/electronics/ecnode.cpp new file mode 100644 index 0000000..0fb2801 --- /dev/null +++ b/src/electronics/ecnode.cpp @@ -0,0 +1,239 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "src/core/ktlconfig.h" +#include "component.h" +#include "connector.h" +#include "ecnode.h" +#include "pin.h" + +#include +#include + +#include + +// The voltage at the middle of the voltage indicator +const double vMidPoint = 5.; + +// The maximum length of the voltage indiactor +const int vLength = 8; + +// The current at the middle of the current indicator +const double iMidPoint = 0.03; + +// The maximum thicnkess of the current indicator +const int iLength = 6; + +inline double calcVProp( const double v ) +{ + return 1 - vMidPoint/(vMidPoint+std::abs(v)); +} + +inline double calcIProp( const double i ) +{ + return 1 - iMidPoint/(iMidPoint+std::abs(i)); +} + +inline int calcThickness( const double prop ) +{ + return (int)((iLength-2)*prop+2); +} + +inline int calcLength( const double prop, const double v ) +{ + return (v>0) ? -int(vLength*prop) : int(vLength*prop); +} + +ECNode::ECNode( ICNDocument *icnDocument, Node::node_type _type, node_dir dir, const QPoint &pos, QString *_id ) + : Node( icnDocument, _type, dir, pos, _id ) +{ + m_prevV = 0; + m_prevI = 0; + m_pinPoint = 0l; + m_bShowVoltageBars = KTLConfig::showVoltageBars(); + + icnDocument->registerItem(this); + + if ( type() == ec_pin ) + { + m_pinPoint = new QCanvasRectangle( 0, 0, 3, 3, canvas() ); + m_pinPoint->setBrush(Qt::black); + m_pinPoint->setPen(Qt::black); + } + + m_pins.resize(1); + m_pins[0] = new Pin(this); +} + + +ECNode::~ECNode() +{ + if (m_pinPoint) + m_pinPoint->setCanvas(0l); + delete m_pinPoint; + m_pinPoint = 0l; + + for ( unsigned i = 0; i < m_pins.size(); i++ ) + delete m_pins[i]; + m_pins.resize(0); +} + + +void ECNode::setNumPins( unsigned num ) +{ + unsigned oldNum = m_pins.size(); + + if ( num == oldNum ) + return; + + if ( num > oldNum ) + { + m_pins.resize(num); + for ( unsigned i = oldNum; i < num; i++ ) + m_pins[i] = new Pin(this); + } + else + { + for ( unsigned i = num; i < oldNum; i++ ) + delete m_pins[i]; + m_pins.resize(num); + } + + emit numPinsChanged(num); +} + + +void ECNode::setNodeChanged() +{ + if ( !canvas() || numPins() != 1 ) + return; + + Pin * pin = m_pins[0]; + + double v = pin->voltage(); + double i = pin->current(); + + if ( v != m_prevV || i != m_prevI ) + { + QRect r = boundingRect(); + r.setCoords( r.left()+(r.width()/2)-1, r.top()+(r.height()/2)-1, r.right()-(r.width()/2)+1, r.bottom()-(r.height()/2)+1 ); + canvas()->setChanged(r); + m_prevV = v; + m_prevI = i; + } +} + + +void ECNode::setParentItem( CNItem * parentItem ) +{ + Node::setParentItem(parentItem); + + if ( Component * component = dynamic_cast(parentItem) ) + { + connect( component, SIGNAL(elementDestroyed(Element* )), this, SLOT(removeElement(Element* )) ); + connect( component, SIGNAL(switchDestroyed( Switch* )), this, SLOT(removeSwitch( Switch* )) ); + } +} + + +void ECNode::removeElement( Element * e ) +{ + for ( unsigned i = 0; i < m_pins.size(); i++ ) + m_pins[i]->removeElement(e); +} + + +void ECNode::removeSwitch( Switch * sw ) +{ + for ( unsigned i = 0; i < m_pins.size(); i++ ) + m_pins[i]->removeSwitch( sw ); +} + + +void ECNode::drawShape( QPainter &p ) +{ + const int _x = int(x()); + const int _y = int(y()); + + if ( type() == ec_junction ) + { +// p.drawRect( _x-2, _y-1, 5, 3 ); +// p.drawRect( _x-1, _y-2, 3, 5 ); + p.drawRect( _x-1, _y-1, 3, 3 ); + return; + } + + if (m_pinPoint) + { + bool drawDivPoint; + QPoint divPoint = findConnectorDivergePoint(&drawDivPoint); + m_pinPoint->setVisible(drawDivPoint); + m_pinPoint->move( divPoint.x()-1, divPoint.y()-1 ); + } + + // Now to draw on our current/voltage bar indicators + + if ( numPins() == 1 ) + { + double v = pin()->voltage(); + double vProp = calcVProp(v); + int length = calcLength( vProp, v ); + + if ( m_bShowVoltageBars && length != 0 ) + { + // we can assume that v != 0 as length != 0 + + QPen oldPen = p.pen(); + + double i = pin()->current(); + double iProp = calcIProp(i); + int thickness = calcThickness(iProp); + + if ( v > 0 ) + p.setPen( QPen( QColor( 255, 166, 0 ), thickness ) ); + + else + p.setPen( QPen( QColor( 0, 136, 255 ), thickness ) ); + + // The node line (drawn at the end of this function) will overdraw + // some of the voltage bar, so we need to adapt the length + if ( v > 0 && (m_dir == Node::dir_up || m_dir == Node::dir_down) ) + length--; + else if ( v < 0 && (m_dir == Node::dir_left || m_dir == Node::dir_right) ) + length++; + + if ( m_dir == Node::dir_right ) + p.drawLine( _x+3, _y, _x+3, _y+length ); + + else if ( m_dir == Node::dir_down ) + p.drawLine( _x, _y+3, _x-length, _y+3 ); + + else if ( m_dir == Node::dir_left ) + p.drawLine( _x-3, _y, _x-3, _y+length ); + + else if ( m_dir == Node::dir_up ) + p.drawLine( _x, _y-3, _x-length, _y-3 ); + + p.setPen(oldPen); + } + } + + QPen pen( p.pen() ); + pen.setWidth( (numPins() > 1) ? 2 : 1 ); + p.setPen(pen); + + if ( m_dir == Node::dir_right ) p.drawLine( _x, _y, _x+8, _y ); + else if ( m_dir == Node::dir_down ) p.drawLine( _x, _y, _x, _y+8 ); + else if ( m_dir == Node::dir_left ) p.drawLine( _x, _y, _x-8, _y ); + else if ( m_dir == Node::dir_up ) p.drawLine( _x, _y, _x, _y-8 ); +} + +#include "ecnode.moc" diff --git a/src/electronics/ecnode.h b/src/electronics/ecnode.h new file mode 100644 index 0000000..6f8f36e --- /dev/null +++ b/src/electronics/ecnode.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef ECNODE_H +#define ECNODE_H + +#include "node.h" + +#include + +class ECNode; +class Element; +class Pin; +class Switch; +class QTimer; + +typedef QValueList ECNodeList; +typedef QValueList ElementList; +typedef QValueVector PinVector; + +/** +@short Electrical node with voltage / current / etc properties +@author David Saxton +*/ +class ECNode : public Node +{ + Q_OBJECT + public: + ECNode( ICNDocument *icnDocument, Node::node_type type, node_dir dir, const QPoint &pos, QString *id = 0L ); + ~ECNode(); + + virtual void setParentItem( CNItem *parentItem ); + virtual void drawShape( QPainter &p ); + /** + * Set the number of pins "contained" in this node. + */ + void setNumPins( unsigned num ); + /** + * @return the number of pins in this node. + * @see setNumPins + */ + unsigned numPins() const { return m_pins.size(); } + PinVector pins() const { return m_pins; } + Pin * pin( unsigned num = 0 ) const { return (num < m_pins.size()) ? m_pins[num] : 0l; } + bool showVoltageBars() const { return m_bShowVoltageBars; } + void setShowVoltageBars( bool show ) { m_bShowVoltageBars = show; } + void setNodeChanged(); + + signals: + void numPinsChanged( unsigned newNum ); + + protected slots: + void removeElement( Element * e ); + void removeSwitch( Switch * sw ); + + protected: + bool m_bShowVoltageBars; + double m_prevV; + double m_prevI; + QCanvasRectangle * m_pinPoint; + PinVector m_pins; +}; + +#endif + + + diff --git a/src/electronics/gpsimprocessor.cpp b/src/electronics/gpsimprocessor.cpp new file mode 100644 index 0000000..1a3b862 --- /dev/null +++ b/src/electronics/gpsimprocessor.cpp @@ -0,0 +1,880 @@ +/*************************************************************************** + * 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 "config.h" +#ifndef NO_GPSIM + +#include "asmparser.h" +#include "debugmanager.h" +#include "flowcodedocument.h" +#include "gpsimprocessor.h" +#include "language.h" +#include "languagemanager.h" +#include "microlibrary.h" +#include "processchain.h" +#include "simulator.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpsim/cod.h" +#include "gpsim/interface.h" +#include "gpsim/gpsim_classes.h" +#include "gpsim/pic-processor.h" +#include "gpsim/registers.h" +#include "gpsim/14bit-registers.h" +#include "gpsim/symbol.h" +#include "gpsim/sim_context.h" + +bool bDoneGpsimInit = false; +bool bUseGUI = true; +// extern "C" void initialize_gpsim(); +// void initialize_gpsim(void); +extern void initialize_commands(); +void initialize_ConsoleUI(); +extern void initialize_readline(); +extern void gui_main(void); +extern void cli_main(); +void gpsim_version() {}; +void quit_gui() {}; + + +//BEGIN class GpsimProcessor +/** +Work around a bug in gpsim: the directory in a filename is recorded twice, e.g. +"/home/david/afile.asm" is recorded as "/home/david//home/david/afile.asm". This +function will remove the duplicated directory path (by searching for a "//"). +*/ +QString sanitizeGpsimFile( QString file ) +{ + int pos = file.find("//"); + if ( pos != -1 ) + { + file.remove( 0, pos + 1 ); + } + return file; +} + + +GpsimProcessor::GpsimProcessor( QString symbolFile, QObject *parent ) + : QObject(parent), + m_symbolFile(symbolFile) +{ + if (!bDoneGpsimInit) + { +#ifndef GPSIM_0_21_4 + initialize_ConsoleUI(); +#endif + initialize_gpsim_core(); + initialization_is_complete(); + + bDoneGpsimInit = true; + } + + m_bCanExecuteNextCycle = true; + m_bIsRunning = false; + m_pPicProcessor = 0l; + m_codLoadStatus = CodUnknown; + m_pRegisterMemory = 0l; + m_debugMode = GpsimDebugger::AsmDebugger; + m_pDebugger[0] = m_pDebugger[1] = 0l; + + Processor * tempProcessor = 0l; + const char * fileName = symbolFile.ascii(); + +#ifdef GPSIM_0_21_4 + switch ( (cod_errors)load_symbol_file( &tempProcessor, fileName ) ) + { + case COD_SUCCESS: + m_codLoadStatus = CodSuccess; + break; + case COD_FILE_NOT_FOUND: + m_codLoadStatus = CodFileNotFound; + break; + case COD_UNRECOGNIZED_PROCESSOR: + m_codLoadStatus = CodUnrecognizedProcessor; + break; + case COD_FILE_NAME_TOO_LONG: + m_codLoadStatus = CodFileNameTooLong; + break; + case COD_LST_NOT_FOUND: + m_codLoadStatus = CodLstNotFound; + break; + case COD_BAD_FILE: + m_codLoadStatus = CodBadFile; + break; + default: + m_codLoadStatus = CodUnknown; + } +#else // GPSIM_0_21_11+ + FILE * pFile = fopen( fileName, "r" ); + if ( !pFile ) + m_codLoadStatus = CodFileUnreadable; + else + m_codLoadStatus = ( ProgramFileTypeList::GetList().LoadProgramFile( & tempProcessor, fileName, pFile ) ) ? CodSuccess : CodFailure; +#endif + + m_pPicProcessor = dynamic_cast(tempProcessor); + + if ( codLoadStatus() == CodSuccess ) + { + m_pRegisterMemory = new RegisterSet( m_pPicProcessor ); + m_pDebugger[0] = new GpsimDebugger( GpsimDebugger::AsmDebugger, this ); + m_pDebugger[1] = new GpsimDebugger( GpsimDebugger::HLLDebugger, this ); + Simulator::self()->attachGpsimProcessor(this); + DebugManager::self()->registerGpsim(this); + } +} + + +GpsimProcessor::~GpsimProcessor() +{ + Simulator::self()->detachGpsimProcessor(this); + delete m_pRegisterMemory; + + if ( m_pDebugger[0] ) + m_pDebugger[0]->deleteLater(); + if ( m_pDebugger[1] ) + m_pDebugger[1]->deleteLater(); +} + + +void GpsimProcessor::displayCodLoadStatus( ) +{ + switch (m_codLoadStatus) + { + case CodSuccess: + break; + case CodFileNotFound: + KMessageBox::sorry( 0l, i18n("The cod file \"%1\" was not found.").arg(m_symbolFile), i18n("File Not Found") ); + break; + case CodUnrecognizedProcessor: + KMessageBox::sorry( 0l, i18n("The processor for cod file \"%1\" is unrecognized.").arg(m_symbolFile), i18n("Unrecognized Processor") ); + break; + case CodFileNameTooLong: + KMessageBox::sorry( 0l, i18n("The file name \"%1\" is too long.").arg(m_symbolFile), i18n("Filename Too Long") ); + break; + case CodLstNotFound: + KMessageBox::sorry( 0l, i18n("The lst file associated with the cod file \"%1\" was not found.").arg(m_symbolFile), i18n("LST File Not Found") ); + break; + case CodBadFile: + KMessageBox::sorry( 0l, i18n("The cod file \"%1\" is bad.").arg(m_symbolFile), i18n("Bad File") ); + break; + case CodFileUnreadable: + KMessageBox::sorry( 0l, i18n("The cod file \"%1\" could not be read from.").arg(m_symbolFile), i18n("Unreadable File") ); + break; + case CodFailure: + case CodUnknown: + KMessageBox::sorry( 0l, i18n("An error occured with the cod file \"%1\".").arg(m_symbolFile), i18n("Error") ); + break; + } +} + + +unsigned GpsimProcessor::programMemorySize() const +{ + return m_pPicProcessor->program_memory_size(); +} + + +QStringList GpsimProcessor::sourceFileList() +{ + QStringList files; + + // Work around nasty bug in gpsim 0.21.4 where nsrc_files value might be used uninitiazed + int max = m_pPicProcessor->files.nsrc_files(); +#ifdef GPSIM_0_21_4 + if ( max > 10 ) + max = 10; +#endif + + for ( int i = 0; i < max; ++i ) + { + if ( !m_pPicProcessor->files[i] ) + continue; + + files << sanitizeGpsimFile( m_pPicProcessor->files[i]->name().c_str() ); + } + + return files; +} + + +void GpsimProcessor::emitLineReached() +{ + m_pDebugger[0]->emitLineReached(); + m_pDebugger[1]->emitLineReached(); +} + + +void GpsimProcessor::setRunning( bool run ) +{ + if ( m_bIsRunning == run ) + return; + + m_bIsRunning = run; + emit runningStatusChanged(run); +} + + +void GpsimProcessor::executeNext() +{ + if ( !m_bIsRunning ) + return; + + if ( !m_bCanExecuteNextCycle ) + { + m_bCanExecuteNextCycle = true; + return; + } + + unsigned long long beforeExecuteCount = get_cycles().get(); + + m_pPicProcessor->step_one(false); // Don't know what the false is for; gpsim ignores its value anyway + + // Some instructions take more than one cycle to execute, so ignore next cycle if this was the case + if ( (get_cycles().get() - beforeExecuteCount) > 1 ) + m_bCanExecuteNextCycle = false; + + currentDebugger()->checkForBreak(); + + // Let's also update the values of RegisterInfo every 50 milliseconds + if ( (beforeExecuteCount % 20000) == 0 ) + registerMemory()->update(); +} + + +void GpsimProcessor::reset() +{ + bool wasRunning = isRunning(); + m_pPicProcessor->reset(SIM_RESET); + setRunning(false); + if (!wasRunning) + { + // If we weren't running before, then the next signal won't have been emitted + emitLineReached(); + } +} + + +MicroInfo * GpsimProcessor::microInfo( ) const +{ + if ( !m_pPicProcessor ) + return 0l; + + return MicroLibrary::self()->microInfoWithID( m_pPicProcessor->name().c_str() ); +} + + +int GpsimProcessor::operandRegister( unsigned address ) +{ + instruction * ins = m_pPicProcessor->program_memory[ address ]; + if ( Register_op * reg = dynamic_cast(ins) ) + return reg->register_address; + return -1; +} + + +int GpsimProcessor::operandLiteral( unsigned address ) +{ + instruction * ins = m_pPicProcessor->program_memory[ address ]; + if ( Literal_op * lit = dynamic_cast(ins) ) + return lit->L; + return -1; +} + + +GpsimProcessor::ProgramFileValidity GpsimProcessor::isValidProgramFile( const QString & programFile ) +{ + if ( !KStandardDirs::exists(programFile) ) + return DoesntExist; + + QString extension = programFile.right( programFile.length() - programFile.findRev('.') - 1 ).lower(); + + if ( extension == "flowcode" || + extension == "asm" || + extension == "cod" || + extension == "basic" || extension == "microbe" || + extension == "c" ) + return Valid; + + if ( extension == "hex" && QFile::exists( QString(programFile).replace(".hex",".cod") ) ) + return Valid; + + return IncorrectType; +} + + +QString GpsimProcessor::generateSymbolFile( const QString &fileName, QObject *receiver, const char *successMember, const char * failMember ) +{ + if ( !isValidProgramFile(fileName) ) + return QString::null; + + QString extension = fileName.right( fileName.length() - fileName.findRev('.') - 1 ).lower(); + + if ( extension == "cod" ) + { + QTimer::singleShot( 0, receiver, successMember ); + return fileName; + } + if ( extension == "hex" ) + { + QTimer::singleShot( 0, receiver, successMember ); + // We've already checked for the existance of the ".cod" file in GpsimProcessor::isValidProgramFile + return QString(fileName).replace(".hex",".cod"); + } + + else if ( extension == "basic" || extension == "microbe" ) + { + compileMicrobe( fileName, receiver, successMember, failMember ); + return QString(fileName).replace( "."+extension, ".cod" ); + } + else if ( extension == "flowcode" ) + { + const QString hexFile = KTempFile( QString::null, ".hex" ).name(); + + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( hexFile ); + o.setInputFiles( fileName ); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::FlowCode_Program ); + + ProcessChain * pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } + + return QString(hexFile).replace( ".hex", ".cod" ); + } + else if ( extension == "asm" ) + { + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( QString(fileName).replace(".asm",".hex")); + o.setInputFiles(fileName); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(fileName), ProcessOptions::ProcessPath::Program ) ); + + ProcessChain *pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } + + return QString(fileName).replace(".asm",".cod"); + } + else if ( extension == "c" ) + { + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( QString(fileName).replace(".c",".hex")); + o.setInputFiles(fileName); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::C_Program ); + + ProcessChain *pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } + + return QString(fileName).replace(".c",".cod"); + } + + if ( failMember ) + QTimer::singleShot( 0, receiver, failMember ); + return QString::null; +} + + +void GpsimProcessor::compileMicrobe( const QString &filename, QObject *receiver, const char * successMember, const char * failMember ) +{ + ProcessOptions o; + o.b_addToProject = false; + o.setTargetFile( QString(filename).replace(".microbe",".hex") ); + o.setInputFiles(filename); + o.setMethod( ProcessOptions::Method::Forget ); + o.setProcessPath( ProcessOptions::ProcessPath::Microbe_Program ); + ProcessChain * pc = LanguageManager::self()->compile(o); + if (receiver) + { + if (successMember) + connect( pc, SIGNAL(successful()), receiver, successMember ); + if (failMember) + connect( pc, SIGNAL(failed()), receiver, failMember ); + } +} +//END class GpsimProcessor + + + +//BEGIN class GpsimDebugger +GpsimDebugger::GpsimDebugger( Type type, GpsimProcessor * gpsim ) + : QObject() +{ + m_pGpsim = gpsim; + m_type = type; + m_pBreakFromOldLine = 0l; + m_addressToLineMap = 0l; + m_stackLevelLowerBreak = -1; + m_addressSize = 0; + + connect( m_pGpsim, SIGNAL(runningStatusChanged(bool )), this, SLOT(gpsimRunningStatusChanged(bool )) ); + + if ( type == HLLDebugger ) + { + const QStringList sourceFileList = m_pGpsim->sourceFileList(); + QStringList::const_iterator sflEnd = sourceFileList.end(); + for ( QStringList::const_iterator it = sourceFileList.begin(); it != sflEnd; ++it ) + { + AsmParser p(*it); + p.parse(this); + } + } + + initAddressToLineMap(); +} + + +GpsimDebugger::~GpsimDebugger() +{ + QValueList debugLinesToDelete; + + for ( unsigned i = 0; i < m_addressSize; ++i ) + { + DebugLine * dl = m_addressToLineMap[i]; + if ( !dl || dl->markedAsDeleted() ) + continue; + + dl->markAsDeleted(); + debugLinesToDelete += dl; + } + + const QValueList::iterator end = debugLinesToDelete.end(); + for ( QValueList::iterator it = debugLinesToDelete.begin(); it != end; ++it ) + delete *it; + + delete [] m_addressToLineMap; +} + + +void GpsimDebugger::gpsimRunningStatusChanged( bool isRunning ) +{ + if (!isRunning) + { + m_stackLevelLowerBreak = -1; + m_pBreakFromOldLine = 0l; + emitLineReached(); + } +} + + +void GpsimDebugger::associateLine( const QString & sourceFile, int sourceLine, const QString & assemblyFile, int assemblyLine ) +{ + if ( assemblyLine < 0 || sourceLine < 0 ) + { + kdWarning() << k_funcinfo << "Invalid lines: assemblyLine="<programMemorySize(); + + delete [] m_addressToLineMap; + m_addressToLineMap = new DebugLine*[m_addressSize]; + memset( m_addressToLineMap, 0, m_addressSize * sizeof(DebugLine*) ); + + if ( m_type == AsmDebugger ) + { + for ( unsigned i = 0; i < m_addressSize; ++i ) + { + int line = m_pGpsim->picProcessor()->pma->get_src_line(i) - 1; + int fileID = m_pGpsim->picProcessor()->pma->get_file_id(i); + FileContext * fileContext = m_pGpsim->picProcessor()->files[fileID]; + + if (fileContext) + m_addressToLineMap[i] = new DebugLine( sanitizeGpsimFile( fileContext->name().c_str() ), line ); + } + } + else + { + SourceLineMap::const_iterator slmEnd = m_sourceLineMap.end(); + for ( SourceLineMap::const_iterator it = m_sourceLineMap.begin(); it != slmEnd; ++it ) + { + SourceLineMap::const_iterator next = it; + ++next; + + int asmToLine = ((next == slmEnd) || (next.key().fileName() != it.key().fileName())) ? -1 : next.key().line() - 1; + + QString asmFile = it.key().fileName(); + int asmFromLine = it.key().line(); + SourceLine sourceLine = it.data(); + + + std::string stdAsmFile( asmFile.ascii() ); + int fileID = m_pGpsim->picProcessor()->files.Find( stdAsmFile ); + if ( fileID == -1 ) + { + kdWarning() << k_funcinfo << "Could not find FileContext (asmFile=\""<picProcessor()->files[fileID]->max_line() - 2; + + if ( (asmFromLine < 0) || (asmToLine < asmFromLine) ) + { + kdWarning() << k_funcinfo << "Invalid lines: asmFromLine="<isRunning() ) + return; + + int initialStack = (m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask) + dl; + DebugLine * initialLine = currentDebugLine(); + + if ( initialStack < 0 ) + initialStack = 0; + + // Reset any previous stackStep, and step + m_pBreakFromOldLine = 0l; + m_stackLevelLowerBreak = -1; + m_pGpsim->picProcessor()->step_one(false); + + int currentStack = m_pGpsim->picProcessor()->stack->pointer & m_pGpsim->picProcessor()->stack->stack_mask; + DebugLine * currentLine = currentDebugLine(); + + if ( (initialStack >= currentStack) && (initialLine != currentLine) ) + emitLineReached(); + + else + { + // Looks like we stepped into something or haven't gone onto the next + // instruction, wait until we step back out.... + m_stackLevelLowerBreak = initialStack; + m_pBreakFromOldLine = initialLine; + m_pGpsim->setRunning(true); + } +} +//END class Debugger + + + +//BEGIN class RegisterSet +RegisterSet::RegisterSet( pic_processor * picProcessor ) +{ + unsigned numRegisters = picProcessor->rma.get_size(); + m_registers.resize( numRegisters, 0l ); + for ( unsigned i = 0; i < numRegisters; ++i ) + { + RegisterInfo * info = new RegisterInfo( & picProcessor->rma[i] ); + m_registers[i] = info; + m_nameToRegisterMap[ info->name() ] = info; + } + + RegisterInfo * info = new RegisterInfo( picProcessor->W ); + m_registers.append( info ); + m_nameToRegisterMap[ info->name() ] = info; +} + + +RegisterSet::~RegisterSet() +{ + for ( unsigned i = 0; i < m_registers.size(); ++i ) + delete m_registers[i]; +} + + +RegisterInfo * RegisterSet::fromAddress( unsigned address ) +{ + return (address < m_registers.size()) ? m_registers[address] : 0l; +} + + +RegisterInfo * RegisterSet::fromName( const QString & name ) +{ + // First try the name as case sensitive, then as case insensitive. + if ( m_nameToRegisterMap.contains( name ) ) + return m_nameToRegisterMap[ name ]; + + QString nameLower = name.lower(); + + RegisterInfoMap::iterator end = m_nameToRegisterMap.end(); + for ( RegisterInfoMap::iterator it = m_nameToRegisterMap.begin(); it != end; ++ it ) + { + if ( it.key().lower() == nameLower ) + return it.data(); + } + + return 0l; +} + + +void RegisterSet::update() +{ + for ( unsigned i = 0; i < m_registers.size(); ++i ) + m_registers[i]->update(); +} +//END class RegisterSet + + + +//BEGIN class RegisterInfo +RegisterInfo::RegisterInfo( Register * reg ) +{ + assert(reg); + m_pRegister = reg; + m_type = Invalid; + m_prevEmitValue = 0; + + switch ( m_pRegister->isa() ) + { + case Register::GENERIC_REGISTER: + m_type = Generic; + break; + case Register::FILE_REGISTER: + m_type = File; + break; + case Register::SFR_REGISTER: + m_type = SFR; + break; + case Register::BP_REGISTER: + m_type = Breakpoint; + break; + case Register::INVALID_REGISTER: + m_type = Invalid; + break; + } + + m_name = m_pRegister->baseName(); +} + + +unsigned RegisterInfo::value() const +{ + return m_pRegister->value.data; +} + + +void RegisterInfo::update() +{ + unsigned newValue = value(); + if ( newValue != m_prevEmitValue ) + { + m_prevEmitValue = newValue; + emit valueChanged(newValue); + } +} + + +QString RegisterInfo::toString( RegisterType type ) +{ + switch ( type ) + { + case Generic: + return i18n("Generic"); + + case File: + return i18n("File"); + + case SFR: + return i18n("SFR"); + + case Breakpoint: + return i18n("Breakpoint"); + + case Invalid: + return i18n("Invalid"); + } + + return i18n("Unknown"); +} +//END class RegisterInfo + + + +//BEGIN class DebugLine +DebugLine::DebugLine( const QString & fileName, int line ) + : SourceLine( fileName, line ) +{ + m_bIsBreakpoint = false; + m_bMarkedAsDeleted = false; +} + + +DebugLine::DebugLine() + : SourceLine() +{ + m_bIsBreakpoint = false; + m_bMarkedAsDeleted = false; +} +//END class DebugLine + + +#include "gpsimprocessor.moc" + +#endif diff --git a/src/electronics/gpsimprocessor.h b/src/electronics/gpsimprocessor.h new file mode 100644 index 0000000..0650fd9 --- /dev/null +++ b/src/electronics/gpsimprocessor.h @@ -0,0 +1,393 @@ +/*************************************************************************** + * 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 "config.h" +#ifndef NO_GPSIM + +#ifndef GPSIMPROCESSOR_H +#define GPSIMPROCESSOR_H + +#include "sourceline.h" + +#include +#include +#include +#include + +class DebugLine; +class GpsimProcessor; +class MicroInfo; +class pic_processor; // from gpsim +class Register; +class RegisterMemoryAccess; + +typedef QMap SourceLineMap; +typedef QMap QStringMap; +typedef QValueList IntList; + + +class DebugLine : public SourceLine +{ + public: + DebugLine(); + DebugLine( const QString & fileName, int line ); + /** + * Whether or not to break when we reach this line. + */ + bool isBreakpoint() const { return m_bIsBreakpoint; } + /** + * Set whether or not to break when we reach this line. + */ + void setBreakpoint( bool breakpoint ) { m_bIsBreakpoint = breakpoint; } + /** + * Used for efficiency purposes by GpsimProcessor. Sets a flag. + */ + void markAsDeleted() { m_bMarkedAsDeleted = true; } + /** + * Used for efficiency purposes by GpsimProcessor. + */ + bool markedAsDeleted() const { return m_bMarkedAsDeleted; } + + protected: + bool m_bIsBreakpoint; + bool m_bMarkedAsDeleted; + + private: + DebugLine( const DebugLine & dl ); + DebugLine & operator = ( const DebugLine & dl ); +}; + + +/** +@short Stores info from gpsim register, used to hide gpsim interface +@author David Saxton +*/ +class RegisterInfo : public QObject +{ + Q_OBJECT + public: + RegisterInfo( Register * reg ); + + enum RegisterType + { + Invalid, + Generic, + File, + SFR, + Breakpoint + }; + + RegisterType type() const { return m_type; } + QString name() const { return m_name; } + unsigned value() const; + static QString toString( RegisterType type ); + + /** + * Checks to see if the value has changed; if so, emit new value. + */ + void update(); + + signals: + void valueChanged( unsigned newValue ); + + protected: + QString m_name; + RegisterType m_type; + Register * m_pRegister; + unsigned m_prevEmitValue; +}; + + +/** +@short Stores information about a set of registers, used to hide gpsim interface. +@author David Saxton +*/ +class RegisterSet +{ + public: + RegisterSet( pic_processor * picProcessor ); + ~RegisterSet(); + + /** + * Calls update for each RegisterInfo in this set. + */ + void update(); + /** + * Returns the number of registers. + */ + unsigned size() const { return m_registers.size(); } + + RegisterInfo * fromAddress( unsigned address ); + RegisterInfo * fromName( const QString & name ); + + protected: + typedef QMap< QString, RegisterInfo * > RegisterInfoMap; + RegisterInfoMap m_nameToRegisterMap; + QValueVector< RegisterInfo * > m_registers; +}; + + +/** +@author David Saxton +*/ +class GpsimDebugger : public QObject +{ + friend class GpsimProcessor; + Q_OBJECT + + public: + enum Type + { + AsmDebugger = 0, + HLLDebugger = 1 + }; + + GpsimDebugger( Type type, GpsimProcessor * gpsim ); + ~GpsimDebugger(); + + GpsimProcessor * gpsim() const { return m_pGpsim; } + + /** + * When an assembly file was generated by a high level language compiler + * like SDCC, it will insert markers like ";#CSRC" that show which line + * of source-code generated the given set of assembly instructions. This + * matches up the assembly file lines with the associated source file + * lines. + */ + void associateLine( const QString & sourceFile, int sourceLine, const QString & assemblyFile, int assemblyLine ); + /** + * Check to see if we've hit a breakpoint or similar; if so, this + * function will stop the execution of the PIC program. + */ + void checkForBreak(); + /** + * Sets the breakpoints used for the given file to exactly those that + * are contained in this list. Breakpoints for other files are not + * affected. + * @param path the location of the file (which gpsim must recognise). + */ + void setBreakpoints( const QString & path, const IntList & lines ); + /** + * Sets / removes the breakpoint at the given line + */ + void setBreakpoint( const QString & path, int line, bool isBreakpoint ); + /** + * Returns the current source line that gpsim is at. By default, this + * will be the corresponding assembly line. That can be overwritten + * using mapAddressBlockToLine. + */ + SourceLine currentLine(); + /** + * Returns a pointer to the debug info for the current line. + */ + DebugLine * currentDebugLine(); + /** + * @return the program address for the given line (or -1 if no such + * line). + */ + int programAddress( const QString & path, int line ); + /** + * Step into the next program line. + */ + void stepInto(); + /** + * Step over the next program instruction. If we are currently running, + * this function will do nothing. Otherwise, it will record the current + * stack level, step, and if the new stack level is <= the initial level + * then return - otherwise, this processor will set a breakpoint for + * stack levels <= initial, and go to running mode. + */ + void stepOver(); + /** + * Similar to stepOver, except we break when the stack level becomes < + * the initial stack level (instead of <= initial). + */ + void stepOut(); + + signals: + /** + * Emitted when a line is reached. By default, this is the line of the + * input assembly file; however, the line associated with an address in + * the PIC memory can be changed with mapAddressBlockToLine. + */ + void lineReached( const SourceLine & sourceLine ); + + protected slots: + void gpsimRunningStatusChanged( bool isRunning ); + + protected: + void initAddressToLineMap(); + void stackStep( int dl ); + void emitLineReached(); + + int m_stackLevelLowerBreak; // Set by step-over, for when the stack level decreases to the one given + SourceLine m_previousAtLineEmit; // Used for working out whether we should emit a new line reached signal + DebugLine ** m_addressToLineMap; + DebugLine * m_pBreakFromOldLine; + GpsimProcessor * m_pGpsim; + Type m_type; + unsigned m_addressSize; + SourceLineMap m_sourceLineMap; // assembly <--> High level language +}; + + +/** +@author David Saxton +*/ +class GpsimProcessor : public QObject +{ + friend class GpsimDebugger; + Q_OBJECT + + public: + /** + * Create a new gpsim processor. After calling this constructor, you + * should always call codLoadStatus() to ensure that the cod file was + * loaded successfully. + */ + GpsimProcessor( QString symbolFile, QObject *parent = 0 ); + ~GpsimProcessor(); + + void setDebugMode( GpsimDebugger::Type mode ) { m_debugMode = mode; } + GpsimDebugger * currentDebugger() const { return m_pDebugger[m_debugMode]; } + + enum CodLoadStatus + { + CodSuccess, + CodFileNotFound, + CodUnrecognizedProcessor, + CodFileNameTooLong, + CodLstNotFound, + CodBadFile, + CodFileUnreadable, + CodFailure, + CodUnknown // Should never be this, but just in case load_symbol_file returns something funny + }; + + enum InstructionType + { + LiteralOp, + BitOp, + RegisterOp, + UnknownOp, + }; + + /** + * @return status of opening the COD file + * @see displayCodLoadStatus + */ + CodLoadStatus codLoadStatus() const { return m_codLoadStatus; } + /** + * Popups a messagebox to the user according to the CodLoadStatus. Will + * only popup a messagebox if the CodLoadStatus wasn't CodSuccess. + */ + void displayCodLoadStatus(); + /** + * Returns a list of source files for the currently running program. + */ + QStringList sourceFileList(); + /** + * Set whether or not to run gpsim. (i.e. whether or not the step + * function should do anything when called with force=false). + */ + void setRunning( bool run ); + /** + * Returns true if running (currently simulating), else gpsim is paused. + */ + bool isRunning() const { return m_bIsRunning; } + /** + * Execute the next program instruction. If we are not in a running + * mode, then this function will do nothing. + */ + void executeNext(); + /** + * Reset all parts of the simulation. Gpsim will not run until + * setRunning(true) is called. Breakpoints are not affected. + */ + void reset(); + /** + * Returns the microinfo describing this processor. + */ + MicroInfo * microInfo() const; + + pic_processor * picProcessor() const { return m_pPicProcessor; } + unsigned programMemorySize() const; + RegisterSet * registerMemory() const { return m_pRegisterMemory; } + /** + * @return the instruction type at the given address. + */ + InstructionType instructionType( unsigned address ); + /** + * @return the address of the operand's register at address if the + * instruction at address is a register operation, and -1 otherwise. + */ + int operandRegister( unsigned address ); + /** + * @return the literal if the instruction at address is a literal + * operation, and -1 otherwise. + */ + int operandLiteral( unsigned address ); + + //BEGIN Convenience functions for PIC files + enum ProgramFileValidity { DoesntExist, IncorrectType, Valid }; + /** + * @return information on the validity of the given program file (either + * DoesntExist, IncorrectType, or Valid). + * @see static QString generateSymbolFile + */ + static ProgramFileValidity isValidProgramFile( const QString & programFile ); + /** + * Converts the file at programFile to a Symbol file for emulation, + * and returns that symbol file's path + * @param programFile The full url to the file + * @param assembled The slot to connect the assembled signal to + * @see static bool isValidProgramFile( const QString &programFile ) + */ + static QString generateSymbolFile( const QString &fileName, QObject *receiver, const char *successMember, const char * failMember = 0l ); + /** + *Compile microbe to output to the given filename + */ + static void compileMicrobe( const QString &filename, QObject *receiver, const char * successMember, const char * failMember = 0l ); + //END convenience functions for PIC files + + signals: + /** + * Emitted when the running status of gpsim changes. + */ + void runningStatusChanged( bool isRunning ); + + protected: + /** + * Calls emitLineReached for each debugger. + */ + void emitLineReached(); + + pic_processor * m_pPicProcessor; + CodLoadStatus m_codLoadStatus; + const QString m_symbolFile; + RegisterSet * m_pRegisterMemory; + GpsimDebugger::Type m_debugMode; + GpsimDebugger * m_pDebugger[2]; // Asm, HLL + + /** + * We are called effectively for each cycle of the cycle of the + * processor. This value is used as some instructions (e.g. goto) take + * two cycles to execute, and so we must ignore one cycle to ensure + * realtime simulation. + */ + bool m_bCanExecuteNextCycle; + + private: + bool m_bIsRunning; +}; + +#endif + +#endif // !NO_GPSIM diff --git a/src/electronics/pin.cpp b/src/electronics/pin.cpp new file mode 100644 index 0000000..56848fc --- /dev/null +++ b/src/electronics/pin.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * 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 "pin.h" + +#include +#include + +Pin::Pin( ECNode * parent ) +{ + assert(parent); + m_pECNode = parent; + m_voltage = 0.; + m_current = 0.; + m_eqId = -2; + m_bCurrentIsKnown = false; + m_groundType = Pin::gt_never; +} + + +Pin::~Pin() +{ + WireList::iterator end = m_inputWireList.end(); + for ( WireList::iterator it = m_inputWireList.begin(); it != end; ++it ) + delete *it; + + end = m_outputWireList.end(); + for ( WireList::iterator it = m_outputWireList.begin(); it != end; ++it ) + delete *it; +} + + +PinList Pin::localConnectedPins( ) const +{ +// kdDebug() << k_funcinfo << "Input wires: "<startPin(); + } + + end = m_outputWireList.end(); + for ( WireList::const_iterator it = m_outputWireList.begin(); it != end; ++it ) + { + if (*it) + pins << (*it)->endPin(); + } + + pins += m_switchConnectedPins; + + return pins; +} + + +void Pin::setSwitchConnected( Pin * pin, bool isConnected ) +{ + if (!pin) + return; + + if (isConnected) + { + if ( !m_switchConnectedPins.contains(pin) ) + m_switchConnectedPins.append(pin); + } + else + m_switchConnectedPins.remove(pin); +} + + +void Pin::addCircuitDependentPin( Pin * pin ) +{ + if ( pin && !m_circuitDependentPins.contains(pin) ) + m_circuitDependentPins.append(pin); +} + + +void Pin::addGroundDependentPin( Pin * pin ) +{ + if ( pin && !m_groundDependentPins.contains(pin) ) + m_groundDependentPins.append(pin); +} + + +void Pin::removeDependentPins() +{ + m_circuitDependentPins.clear(); + m_groundDependentPins.clear(); +} + + +void Pin::addElement( Element * e ) +{ + if ( !e || m_elementList.contains(e) ) + return; + m_elementList.append(e); +} + + +void Pin::removeElement( Element * e ) +{ + m_elementList.remove(e); +} + + +void Pin::addSwitch( Switch * sw ) +{ + if ( !sw || m_switchList.contains( sw ) ) + return; + m_switchList << sw; +} + + +void Pin::removeSwitch( Switch * sw ) +{ + m_switchList.remove( sw ); +} + + +void Pin::addInputWire( Wire * wire ) +{ + if ( wire && !m_inputWireList.contains(wire) ) + m_inputWireList << wire; +} + + +void Pin::addOutputWire( Wire * wire ) +{ + if ( wire && !m_outputWireList.contains(wire) ) + m_outputWireList << wire; +} + + +bool Pin::calculateCurrentFromWires() +{ + m_inputWireList.remove( (Wire*)0l ); + m_outputWireList.remove( (Wire*)0l ); + + const WireList inputs = m_inputWireList; + const WireList outputs = m_outputWireList; + + m_current = 0.0; + + WireList::const_iterator end = inputs.end(); + for ( WireList::const_iterator it = inputs.begin(); it != end; ++it ) + { + if ( !(*it)->currentIsKnown() ) + return false; + + m_current -= (*it)->current(); + } + + end = outputs.end(); + for ( WireList::const_iterator it = outputs.begin(); it != end; ++it ) + { + if ( !(*it)->currentIsKnown() ) + return false; + + m_current += (*it)->current(); + } + + m_bCurrentIsKnown = true; + return true; +} + diff --git a/src/electronics/pin.h b/src/electronics/pin.h new file mode 100644 index 0000000..1e10663 --- /dev/null +++ b/src/electronics/pin.h @@ -0,0 +1,211 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef PIN_H +#define PIN_H + +#include "wire.h" + +#include +#include +#include + +class ECNode; +class Element; +class Pin; +class Switch; +class Wire; + +typedef QValueList ElementList; +typedef QValueList > PinList; +typedef QValueList SwitchList; +typedef QValueList > WireList; + + +/** +@author David Saxton +*/ +class Pin : public QObject +{ + public: + /** + * Priorities for ground pin. gt_always will (as expected) always assign + * the given pin as ground, gt_never will never do. If no gt_always pins + * exist, then the pin with the highest priority will be set as ground - + * if there is at least one pin that is not of ground type gt_never. These + * are only predefined recommended values, so if you choose not to use one + * of these, please respect the priorities with respect to the examples, and + * always specify a priority between 0 and 20. + * @see groundLevel + */ + enum GroundType + { + gt_always = 0, // ground + gt_high = 5, // voltage points + gt_medium = 10, // voltage sources + gt_low = 15, // current sources + gt_never = 20 // everything else + }; + Pin( ECNode * parent ); + ~Pin(); + + ECNode * parentECNode() const { return m_pECNode; } + /** + * This function returns the pins that are directly connected to this pins: + * either at the ends of connected wires, or via switches. + */ + PinList localConnectedPins() const; + /** + * Adds/removes the given pin to the list of ones that this pin is/isn't + * connected to via a switch. + */ + void setSwitchConnected( Pin * pin, bool isConnected ); + /** + * After calculating the nodal voltages in the circuit, this function should + * be called to tell the pin what its voltage is. + */ + void setVoltage( double v ) { m_voltage = v; } + /** + * Returns the voltage as set by setVoltage. + */ + double voltage() const { return m_voltage; } + /** + * After calculating nodal voltages, each component will be called to tell + * its pins what the current flowing *into* the component is. This sets it + * to zero in preparation to merging the current. + */ + void resetCurrent() { m_current = 0.0; } + /** + * Adds the given current to that already flowing into the pin. + * @see setCurrent + */ + void mergeCurrent( double i ) { m_current += i; } + /** + * Returns the current as set by mergeCurrent. + */ + double current() const { return m_current; } + /** + * In many cases (such as if this pin is a ground pin), the current + * flowing into the pin has not been calculated, and so the value + * returned by current() cannot be trusted. + */ + void setCurrentKnown( bool isKnown ) { m_bCurrentIsKnown = isKnown; } + /** + * Tell thie Pin that none of the currents from the switches have yet + * been merged. + */ + void setSwitchCurrentsUnknown() { m_switchList.remove( 0l ); m_unknownSwitchCurrents = m_switchList; } + /** + * This returns the value given by setCurrentKnown AND'd with whether + * we know the current from each switch attached to this pin. + * @see setCurrentKnown + */ + bool currentIsKnown() const { return m_bCurrentIsKnown && m_unknownSwitchCurrents.isEmpty(); } + /** + * Tells the Pin that the current from the given switch has been merged. + */ + void setSwitchCurrentKnown( Switch * sw ) { m_unknownSwitchCurrents.remove( sw ); } + /** + * Tries to calculate the Pin current from the input / output wires. + * @return whether was successful. + */ + bool calculateCurrentFromWires(); + /** + * Sets the "ground type" - i.e. the priority that this pin has for being + * ground over other pins in the circuit. Lower gt = higher priority. It's + * recommended to use Pin::GroundType. + */ + void setGroundType( int gt ) { m_groundType = gt; } + /** + * Returns the priority for ground. + */ + int groundType() const { return m_groundType; } + /** + * Adds a dependent pin - one whose voltages will (or might) affect the + * voltage of this pin. This is set by Component. + */ + void addCircuitDependentPin( Pin * pin ); + /** + * Adds a dependent pin - one whose voltages will (or might) affect the + * voltage of this pin. This is set by Component. + */ + void addGroundDependentPin( Pin * pin ); + /** + * Removes all Circuit and Ground dependent pins. + */ + void removeDependentPins(); + /** + * Returns the ids of the pins whose voltages will affect this pin. + * @see void setDependentPins( QStringList ids ) + */ + PinList circuitDependentPins() const { return m_circuitDependentPins; } + /** + * Returns the ids of the pins whose voltages will affect this pin. + * @see void setDependentPins( QStringList ids ) + */ + PinList groundDependentPins() const { return m_groundDependentPins; } + /** + * Use this function to set the pin identifier for equations, + * which should be done every time new pins are registered. + */ + void setEqId( int id ) { m_eqId = id; } + /** + * The equation identifier. + * @see setEqId + */ + int eqId() const { return m_eqId; } + /** + * Returns a list of elements that will affect this pin (e.g. if this + * pin is part of a resistor, then that list will contain a pointer to a + * Resistance element) + */ + ElementList elements() const { return m_elementList; } + /** + * Adds an element to the list of those that will affect this pin. + */ + void addElement( Element *e ); + /** + * Removes an element from the list of those that will affect this pin. + */ + void removeElement( Element *e ); + /** + * Adds an switch to the list of those that will affect this pin. + */ + void addSwitch( Switch *e ); + /** + * Removes an switch from the list of those that will affect this pin. + */ + void removeSwitch( Switch *e ); + + void addInputWire( Wire * wire ); + void addOutputWire( Wire * wire ); + void removeWire( Wire * wire ); + WireList inputWireList() const { return m_inputWireList; } + WireList outputWireList() const { return m_outputWireList; } + int numWires() const { return m_inputWireList.size() + m_outputWireList.size(); } + + protected: + double m_voltage; + double m_current; + int m_eqId; + bool m_bCurrentIsKnown; + PinList m_circuitDependentPins; + PinList m_groundDependentPins; + ElementList m_elementList; + SwitchList m_switchList; + int m_groundType; + PinList m_switchConnectedPins; + WireList m_inputWireList; + WireList m_outputWireList; + ECNode * m_pECNode; + SwitchList m_unknownSwitchCurrents; +}; + +#endif diff --git a/src/electronics/port.cpp b/src/electronics/port.cpp new file mode 100644 index 0000000..541195b --- /dev/null +++ b/src/electronics/port.cpp @@ -0,0 +1,514 @@ +/*************************************************************************** + * 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 "port.h" + +#include + +#include +#include +#include +#include +#include + +//BEGIN class Port +Port::Port() +{ +} + + +Port::~Port() +{ +} + + +QStringList Port::ports( unsigned probeResult ) +{ + return SerialPort::ports(probeResult) + ParallelPort::ports(probeResult); +} +//END class Port + + + +//BEGIN class SerialPort +SerialPort::SerialPort() +{ + m_file = -1; +} + + +SerialPort::~SerialPort() +{ + closePort(); +} + + +void SerialPort::setPinState( Pin pin, bool state ) +{ + if ( m_file == -1 ) + return; + + int flags = -1; + + switch ( pin ) + { + case TD: + ioctl( m_file, state ? TIOCSBRK : TIOCCBRK, 0 ); + return; + + case DTR: + flags = TIOCM_DTR; + break; + + case DSR: + flags = TIOCM_DSR; + break; + + case RTS: + flags = TIOCM_RTS; + break; + + case CD: + case RD: + case GND: + case CTS: + case RI: + break; + }; + + if ( flags == -1 ) + { + kdError() << k_funcinfo << "Bad pin " << pin << endl; + return; + } + + if ( ioctl( m_file, state ? TIOCMBIS : TIOCMBIC, & flags ) == -1 ) + kdError() << k_funcinfo << "Could not set pin " << pin << " errno = " << errno << endl; +} + + +bool SerialPort::pinState( Pin pin ) +{ + if ( m_file == -1 ) + return false; + + int mask = 0; + + switch ( pin ) + { + case CD: + mask = TIOCM_CD; + break; + + case RD: + mask = TIOCM_SR; + break; + + case CTS: + mask = TIOCM_CTS; + break; + + case RI: + mask = TIOCM_RI; + break; + + case TD: + case DTR: + case GND: + case DSR: + case RTS: + break; + } + + if ( mask == 0 ) + { + kdError() << k_funcinfo << "Bad pin " << pin << endl; + return false; + } + + int bits = 0; + if ( ioctl( m_file, TIOCMGET, & bits ) == -1 ) + { + kdError() << k_funcinfo << "Could not read pin" << pin << " errno = " << errno << endl; + return false; + } + + return bits & mask; +} + + +Port::ProbeResult SerialPort::probe( const QString & port ) +{ + int file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDONLY ); + if ( file == -1 ) + return Port::DoesntExist; + + close(file); + + file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR ); + if ( file == -1 ) + return Port::ExistsButNotRW; + close(file); + + return Port::ExistsAndRW; +} + + +bool SerialPort::openPort( const QString & port, speed_t baudRate ) +{ + closePort(); + + m_file = open( port.ascii(), O_NOCTTY | O_NONBLOCK | O_RDWR ); + if ( m_file == -1 ) + { + kdError() << k_funcinfo << "Could not open port " << port << endl; + return false; + } + + termios state; + tcgetattr( m_file, & state ); + + // Save the previous state for restoration in close. + m_previousState = state; + + state.c_iflag = IGNBRK | IGNPAR; + state.c_oflag = 0; + state.c_cflag = baudRate | CS8 | CREAD | CLOCAL; + state.c_lflag = 0; + tcsetattr( m_file, TCSANOW, & state ); + + return true; +} + + +void SerialPort::closePort() +{ + if ( m_file == -1 ) + return; + + ioctl( m_file, TIOCCBRK, 0 ); + usleep(1); + tcsetattr( m_file, TCSANOW, & m_previousState ); + close( m_file ); + m_file = -1; +} + + +QStringList SerialPort::ports( unsigned probeResult ) +{ + QStringList list; + + for ( int i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/ttyS%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/tts/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/ttyUSB%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/usb/tts/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + return list; +} +//END class SerialPort + + + +//BEGIN class ParallelPort +const int IRQ_MODE_BIT = 1 << 20; // Controls if pin 10 (Ack) causes interrupts +const int INPUT_MODE_BIT = 1 << 21; // Controls if the data pins are input or output +const int ALWAYS_INPUT_PINS = ParallelPort::STATUS_PINS; + +const int IOCTL_REG_READ[3] = { + PPRDATA, + PPRSTATUS, + PPRCONTROL, +}; + +const int IOCTL_REG_WRITE[3] = { + PPWDATA, + 0, + PPWCONTROL, +}; + +const int INVERT_MASK[3] = { + 0x0, + 0x80, // 10000000 + 0x0b, // 00001011 +}; + +ParallelPort::ParallelPort() +{ + reset(); +} + + +ParallelPort::~ParallelPort() +{ +} + + +void ParallelPort::reset() +{ + m_file = -1; + m_reg[Data] = 0; + m_reg[Status] = 0; + m_reg[Control] = 0; + m_outputPins = INPUT_MODE_BIT | IRQ_MODE_BIT; + m_inputPins = ALWAYS_INPUT_PINS | INPUT_MODE_BIT | IRQ_MODE_BIT; +} + + +//BEGIN Pin-oriented operations +void ParallelPort::setPinState( int pins, bool state ) +{ + // only allow writing to output pins + pins &= m_outputPins; + + if ( pins & DATA_PINS ) + setDataState( (pins & DATA_PINS) >> 0, state ); + + if ( pins & CONTROL_PINS ) + setControlState( (pins & CONTROL_PINS) >> 16, state ); +} + + +int ParallelPort::pinState( int pins ) +{ + int value = 0; + + // only allow reading from input pins + pins &= m_inputPins; + + if ( pins & DATA_PINS ) + value |= ((readFromRegister( Data ) & ((pins & DATA_PINS) >> 0)) << 0); + + if ( pins & STATUS_PINS ) + value |= ((readFromRegister( Status ) & ((pins & STATUS_PINS) >> 8)) << 8); + + if ( pins & CONTROL_PINS ) + value |= ((readFromRegister( Control ) & ((pins & CONTROL_PINS) >> 16)) << 16); + + return value; +} + + +void ParallelPort::setDataState( uchar pins, bool state ) +{ + uchar value = readFromRegister( Data ); + + if ( state ) + value |= pins; + else + value &= ~pins; + + writeToData( value ); +} + + +void ParallelPort::setControlState( uchar pins, bool state ) +{ + uchar value = readFromRegister( Control ); + + if ( state ) + value |= pins; + else + value &= ~pins; + + writeToControl( value ); +} +//END Pin-oriented operations + + + +//BEGIN Register-oriented operations +uchar ParallelPort::readFromRegister( Register reg ) +{ + if ( m_file == -1 ) + return 0; + +// uchar value = inb( m_lpBase + reg ) ^ INVERT_MASK[reg]; + uchar value = 0; + if ( ioctl( m_file, IOCTL_REG_READ[reg], &value ) ) + kdError() << k_funcinfo << "errno=" << errno << endl; + else + m_reg[reg] = value; + return value; +} + + +void ParallelPort::writeToRegister( Register reg, uchar value ) +{ + if ( m_file == -1 ) + return; + +// outb( value ^ INVERT_MASK[reg], m_lpBase + reg ); + if ( ioctl( m_file, IOCTL_REG_WRITE[reg], & value ) ) + kdError() << k_funcinfo << "errno=" << errno << endl; + else + m_reg[reg] = value; +} + + +void ParallelPort::writeToData( uchar value ) +{ + writeToRegister( Data, value ); +} + + +void ParallelPort::writeToControl( uchar value ) +{ + // Set all inputs to ones + value |= ((m_inputPins & CONTROL_PINS) >> 16); + + writeToRegister( Control, value ); +} +//END Register-oriented operations + + +//BEGIN Changing pin directions +void ParallelPort::setDataDirection( Direction dir ) +{ + if ( dir == Input ) + { + m_inputPins |= DATA_PINS; + m_outputPins &= ~DATA_PINS; + } + else + { + m_inputPins &= DATA_PINS; + m_outputPins |= ~DATA_PINS; + } + + setPinState( INPUT_MODE_BIT, dir == Input ); +} + + +void ParallelPort::setControlDirection( int pins, Direction dir ) +{ + pins &= CONTROL_PINS; + + if ( dir == Input ) + { + m_inputPins |= pins; + m_outputPins &= ~pins; + } + else + { + m_inputPins &= pins; + m_outputPins |= ~pins; + } + + setControlState( 0, true ); +} +//END Changing pin directions + + +Port::ProbeResult ParallelPort::probe( const QString & port ) +{ + int file = open( port.ascii(), O_RDWR ); + if ( file == -1 ) + return Port::DoesntExist; + + if ( ioctl( file, PPCLAIM ) != 0 ) + { + close(file); + return Port::ExistsButNotRW; + } + + ioctl( file, PPRELEASE ); + close(file); + return Port::ExistsAndRW; +} + + +QStringList ParallelPort::ports( unsigned probeResult ) +{ + QStringList list; + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/parport%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + for ( unsigned i = 0; i < 8; ++i ) + { + QString dev = QString("/dev/parports/%1").arg(i); + if ( probe(dev) & probeResult ) + list << dev; + } + + return list; +} + + +bool ParallelPort::openPort( const QString & port ) +{ + if ( m_file != -1 ) + { + kdWarning() << k_funcinfo << "Port already open" << endl; + return false; + } + + m_file = open( port.ascii(), O_RDWR ); + + if ( m_file == -1 ) + { + kdError() << k_funcinfo << "Could not open port \"" << port << "\": errno="< +using namespace std; + + +//BEGIN class BJTSettings +BJTSettings::BJTSettings() +{ + I_S = 1e-16; + N_F = 1.0; + N_R = 1.0; + B_F = 100.0; + B_R = 1.0; +} +//END class BJTSettings + + + +//BEGIN class BJTState +BJTState::BJTState() +{ + reset(); +} + + +void BJTState::reset() +{ + for ( unsigned i = 0; i < 3; ++i ) + { + for ( unsigned j = 0; j < 3; ++j ) + A[i][j] = 0.0; + + I[i] = 0.0; + } +} + + +BJTState BJTState::operator-( const BJTState & s ) const +{ + BJTState newState( *this ); + + for ( unsigned i = 0; i < 3; ++i ) + { + for ( unsigned j = 0; j < 3; ++j ) + newState.A[i][j] -= s.A[i][j]; + + newState.I[i] -= s.I[i]; + } + + return newState; +} +//END class BJTState + + + +//BEGIN class BJT +BJT::BJT( const bool isNPN ) + : NonLinear() +{ + V_BE_prev = 0.0; + V_BC_prev = 0.0; + m_pol = isNPN ? 1 : -1; + m_numCNodes = 3; +} + + +BJT::~BJT() +{ +} + + +void BJT::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse( p_cnode[2]->n(), p_cnode[2]->n(), Map::et_unstable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[2]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[2]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[2]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround && !p_cnode[2]->isGround ) + { + p_A->setUse( p_cnode[2]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[2]->n(), Map::et_unstable, false ); + } +} + + +void BJT::add_initial_dc() +{ + V_BE_prev = 0.0; + V_BC_prev = 0.0; + m_os.reset(); + update_dc(); +} + + +void BJT::updateCurrents() +{ + if (!b_status) + return; + + double V_B = p_cnode[0]->v; + double V_C = p_cnode[1]->v; + double V_E = p_cnode[2]->v; + + double V_BE = (V_B - V_E) * m_pol; + double V_BC = (V_B - V_C) * m_pol; + + double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR; + calcIg( V_BE, V_BC, & I_BE, & I_BC, & I_T, & g_BE, & g_BC, & g_IF, & g_IR ); + + m_cnodeI[1] = I_BC - I_T; + m_cnodeI[2] = I_BE + I_T; + m_cnodeI[0] = -(m_cnodeI[1] + m_cnodeI[2]); +} + + +void BJT::update_dc() +{ + if (!b_status) + return; + + calc_eq(); + + BJTState diff = m_ns - m_os; + for ( unsigned i = 0; i < 3; ++i ) + { + for ( unsigned j = 0 ; j < 3; ++j ) + A_g( i, j ) += diff.A[i][j]; + + b_i( i ) += diff.I[i]; + } + + m_os = m_ns; +} + + +void BJT::calc_eq() +{ + double V_B = p_cnode[0]->v; + double V_C = p_cnode[1]->v; + double V_E = p_cnode[2]->v; + + double V_BE = (V_B - V_E) * m_pol; + double V_BC = (V_B - V_C) * m_pol; + + double I_S = m_bjtSettings.I_S; + double N_F = m_bjtSettings.N_F; + double N_R = m_bjtSettings.N_R; + + // adjust voltage to help convergence + double V_BEcrit = diodeCriticalVoltage( I_S, N_F * V_T ); + double V_BCcrit = diodeCriticalVoltage( I_S, N_R * V_T ); + V_BE_prev = V_BE = diodeVoltage( V_BE, V_BE_prev, V_T * N_F, V_BEcrit ); + V_BC_prev = V_BC = diodeVoltage( V_BC, V_BC_prev, V_T * N_R, V_BCcrit ); + + double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR; + calcIg( V_BE, V_BC, & I_BE, & I_BC, & I_T, & g_BE, & g_BC, & g_IF, & g_IR ); + + double I_eq_B = I_BE - V_BE * g_BE; + double I_eq_C = I_BC - V_BC * g_BC; + double I_eq_E = I_T - V_BE * g_IF + V_BC * g_IR; + + m_ns.A[0][0] = g_BC + g_BE; + m_ns.A[0][1] = -g_BC; + m_ns.A[0][2] = -g_BE; + + m_ns.A[1][0] = -g_BC + (g_IF - g_IR); + m_ns.A[1][1] = g_IR + g_BC; + m_ns.A[1][2] = -g_IF; + + m_ns.A[2][0] = -g_BE - (g_IF - g_IR); + m_ns.A[2][1] = -g_IR; + m_ns.A[2][2] = g_BE + g_IF; + + m_ns.I[0] = (-I_eq_B - I_eq_C) * m_pol; + m_ns.I[1] = (+I_eq_C - I_eq_E) * m_pol; + m_ns.I[2] = (+I_eq_B + I_eq_E) * m_pol; +} + + +void BJT::calcIg( double V_BE, double V_BC, double * I_BE, double * I_BC, double * I_T, double * g_BE, double * g_BC, double * g_IF, double * g_IR ) +{ + double I_S = m_bjtSettings.I_S; + double N_F = m_bjtSettings.N_F; + double N_R = m_bjtSettings.N_R; + double B_F = m_bjtSettings.B_F; + double B_R = m_bjtSettings.B_R; + + // base-emitter diodes + double g_tiny = (V_BE < (-10 * V_T * N_F)) ? I_S : 0; + + double I_F; + diodeJunction( V_BE, I_S, V_T * N_F, & I_F, g_IF ); + + double I_BEI = I_F / B_F; + double g_BEI = *g_IF / B_F; + double I_BEN = g_tiny * V_BE; + double g_BEN = g_tiny; + *I_BE = I_BEI + I_BEN; + *g_BE = g_BEI + g_BEN; + + // base-collector diodes + g_tiny = (V_BC < (-10 * V_T * N_R)) ? I_S : 0; + + double I_R; + diodeJunction( V_BC, I_S, V_T * N_R, & I_R, g_IR ); + + double I_BCI = I_R / B_R; + double g_BCI = *g_IR / B_R; + double I_BCN = g_tiny * V_BC; + double g_BCN = g_tiny; + *I_BC = I_BCI + I_BCN; + *g_BC = g_BCI + g_BCN; + + *I_T = I_F - I_R; +} + + +void BJT::setBJTSettings( const BJTSettings & settings ) +{ + m_bjtSettings = settings; + + if (p_eSet) + p_eSet->setCacheInvalidated(); +} +//END class BJT + + diff --git a/src/electronics/simulation/bjt.h b/src/electronics/simulation/bjt.h new file mode 100644 index 0000000..52022aa --- /dev/null +++ b/src/electronics/simulation/bjt.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef BJT_H +#define BJT_H + +#include "matrix.h" +#include "nonlinear.h" + +class BJTState +{ + public: + BJTState(); + void reset(); + + BJTState operator-( const BJTState & s ) const; + + double A[3][3]; + double I[3]; +}; + + +class BJTSettings +{ + public: + BJTSettings(); + + double I_S; ///< saturation current + double N_F; ///< forward emission coefficient + double N_R; ///< reverse emission coefficient + double B_F; ///< forward beta + double B_R; ///< reverse beta +}; + + +/** +@author David Saxton +*/ +class BJT : public NonLinear +{ + public: + BJT( bool isNPN ); + virtual ~BJT(); + + virtual Type type() const { return Element_BJT; } + virtual void update_dc(); + virtual void add_initial_dc(); + virtual void add_map(); + BJTSettings settings() const { return m_bjtSettings; } + void setBJTSettings( const BJTSettings & settings ); + + protected: + virtual void updateCurrents(); + /** + * Calculates the new BJTState from the voltages on the nodes. + */ + void calc_eq(); + + void calcIg( double V_BE, double V_BC, double * I_BE, double * I_BC, double * I_T, double * g_BE, double * g_BC, double * g_IF, double * g_IR ); + + BJTState m_os; + BJTState m_ns; + int m_pol; + double V_BE_prev, V_BC_prev; + BJTSettings m_bjtSettings; +}; + +#endif diff --git a/src/electronics/simulation/capacitance.cpp b/src/electronics/simulation/capacitance.cpp new file mode 100644 index 0000000..9087c7f --- /dev/null +++ b/src/electronics/simulation/capacitance.cpp @@ -0,0 +1,117 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "capacitance.h" +#include "matrix.h" + +Capacitance::Capacitance( const double capacitance, const double delta ) + : Reactive(delta) +{ + m_cap = capacitance; + g_eq_old = i_eq_old = 0.; + m_numCNodes = 2; + setMethod( Capacitance::m_euler ); +} + +Capacitance::~Capacitance() +{ +} + +void Capacitance::setCapacitance( const double c ) +{ + m_cap = c; +} + +void Capacitance::add_initial_dc() +{ + // We don't need to do anything here, as time_step() will do that for us, + // apart from to make sure our old values are 0 + g_eq_old = i_eq_old = 0.; +} + +void Capacitance::updateCurrents() +{ + if (!b_status) return; + const double r_i = (p_cnode[0]->v-p_cnode[1]->v)*g_eq_old; + m_cnodeI[0] = -i_eq_old-r_i; + m_cnodeI[1] = -m_cnodeI[0]; +} + + +void Capacitance::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } +} + + +void Capacitance::time_step() +{ + if (!b_status) return; + + double v = p_cnode[0]->v-p_cnode[1]->v; + double i_eq_new = 0.0, g_eq_new = 0.0; + + if ( m_method == Capacitance::m_euler ) + { + g_eq_new = m_cap/m_delta; + i_eq_new = -v*g_eq_new; + } + else if ( m_method == Capacitance::m_trap ) { + // TODO Implement + test trapezoidal method + g_eq_new = 2.*m_cap/m_delta; + } + + if ( g_eq_old != g_eq_new ) + { + A_g( 0, 0 ) += g_eq_new-g_eq_old; + A_g( 1, 1 ) += g_eq_new-g_eq_old; + A_g( 0, 1 ) -= g_eq_new-g_eq_old; + A_g( 1, 0 ) -= g_eq_new-g_eq_old; + } + + if ( i_eq_new != i_eq_old ) + { + b_i( 0 ) -= i_eq_new-i_eq_old; + b_i( 1 ) += i_eq_new-i_eq_old; + } + + g_eq_old = g_eq_new; + i_eq_old = i_eq_new; +} + +bool Capacitance::updateStatus() +{ + b_status = Reactive::updateStatus(); + if ( m_method == Capacitance::m_none ) b_status = false; + return b_status; +} + +void Capacitance::setMethod( Method m ) +{ + m_method = m; + updateStatus(); +} + + diff --git a/src/electronics/simulation/capacitance.h b/src/electronics/simulation/capacitance.h new file mode 100644 index 0000000..ccc083d --- /dev/null +++ b/src/electronics/simulation/capacitance.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef CAPACITANCE_H +#define CAPACITANCE_H + +#include "reactive.h" + +/** +@author David Saxton +@short Capacitance +*/ +class Capacitance : public Reactive +{ +public: + enum Method + { + m_none, // None + m_euler, // Backward Euler + m_trap // Trapezoidal (currently unimplemented) + }; + Capacitance( const double capacitance, const double delta ); + virtual ~Capacitance(); + + virtual Type type() const { return Element_Capacitance; } + /** + * Set the stepping use for numerical integration of capacitance, + * and the interval between successive updates + */ + void setMethod( Method m ); + virtual void time_step(); + virtual void add_initial_dc(); + void setCapacitance( const double c ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual bool updateStatus(); + +private: + double m_cap; // Capacitance + Method m_method; // Method of integration + + double g_eq_old; + double i_eq_old; +}; + +#endif diff --git a/src/electronics/simulation/cccs.cpp b/src/electronics/simulation/cccs.cpp new file mode 100644 index 0000000..9725735 --- /dev/null +++ b/src/electronics/simulation/cccs.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "elementset.h" +#include "matrix.h" +#include "cccs.h" + +CCCS::CCCS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 2; + m_numCNodes = 4; +} + +CCCS::~CCCS() +{ +} + +void CCCS::setGain( const double g ) +{ + if ( m_g == g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_g = g; + add_initial_dc(); +} + + +void CCCS::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + } + p_A->setUse_d( p_cbranch[1]->n(), p_cbranch[0]->n(), Map::et_stable, true ); + p_A->setUse_d( p_cbranch[1]->n(), p_cbranch[1]->n(), Map::et_constant, true ); +} + +void CCCS::add_initial_dc() +{ + if (!b_status) + return; + + A_b( 0, 0 ) = 1; + A_c( 0, 0 ) = 1; + A_b( 1, 0 ) = -1; + A_c( 0, 1 ) = -1; + A_b( 2, 1 ) = 1; + A_b( 3, 1 ) = -1; + A_d( 1, 0 ) = -m_g; + A_d( 1, 1 ) = 1; +} + +void CCCS::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[1] = p_cbranch[0]->i; + m_cnodeI[0] = -m_cnodeI[1]; + m_cnodeI[3] = p_cbranch[1]->i; + m_cnodeI[2] = -m_cnodeI[3]; +} + diff --git a/src/electronics/simulation/cccs.h b/src/electronics/simulation/cccs.h new file mode 100644 index 0000000..ba86e9e --- /dev/null +++ b/src/electronics/simulation/cccs.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef CCCS_H +#define CCCS_H + +#include "element.h" + +/** +CNodes n0 and n1 are used for the current control. +CNodes n2 and n3 are used for the current output. +Branches b0 and b1 are for control and output +@short Current Controlled Current Source +@author David Saxton +*/ +class CCCS : public Element +{ +public: + CCCS( const double gain ); + virtual ~CCCS(); + + virtual Type type() const { return Element_CCCS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/ccvs.cpp b/src/electronics/simulation/ccvs.cpp new file mode 100644 index 0000000..fc12bf5 --- /dev/null +++ b/src/electronics/simulation/ccvs.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "elementset.h" +#include "matrix.h" +#include "ccvs.h" + +CCVS::CCVS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 2; + m_numCNodes = 4; +} + +CCVS::~CCVS() +{ +} + +void CCVS::setGain( const double g ) +{ + if ( m_g == g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_g = g; + add_initial_dc(); +} + + +void CCVS::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[1]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[1]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[1]->n(), p_cnode[3]->n(), Map::et_constant, true ); + } + p_A->setUse_d( p_cbranch[1]->n(), p_cbranch[0]->n(), Map::et_stable, true ); +} + + +void CCVS::add_initial_dc() +{ + if (!b_status) return; + + A_b( 0, 0 ) = 1; + A_c( 0, 0 ) = 1; + A_b( 1, 0 ) = -1; + A_c( 0, 1 ) = -1; + A_b( 2, 1 ) = 1; + A_c( 1, 2 ) = 1; + A_b( 3, 1 ) = -1; + A_c( 1, 3 ) = -1; + A_d( 1, 0 ) = -m_g; +} + +void CCVS::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[1] = p_cbranch[0]->i; + m_cnodeI[0] = -m_cnodeI[1]; + m_cnodeI[3] = p_cbranch[0]->i; + m_cnodeI[2] = -m_cnodeI[3]; +} + diff --git a/src/electronics/simulation/ccvs.h b/src/electronics/simulation/ccvs.h new file mode 100644 index 0000000..bcb1ac0 --- /dev/null +++ b/src/electronics/simulation/ccvs.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef CCVS_H +#define CCVS_H + +#include "element.h" + +/** +CNodes n0 and n1 are used for the current control. +CNodes n2 and n3 are used for the voltage output. +Branches b0 and b1 are for control and output +@short Current Controlled Voltage Source +@author David Saxton +*/ +class CCVS : public Element +{ +public: + CCVS( const double gain ); + virtual ~CCVS(); + + virtual Type type() const { return Element_CCVS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/circuit.cpp b/src/electronics/simulation/circuit.cpp new file mode 100644 index 0000000..c152756 --- /dev/null +++ b/src/electronics/simulation/circuit.cpp @@ -0,0 +1,550 @@ +/*************************************************************************** + * Copyright (C) 2003-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 +#include "circuit.h" +#include "circuitdocument.h" +#include "element.h" +#include "elementset.h" +#include "logic.h" +#include "matrix.h" +#include "nonlinear.h" +#include "pin.h" +#include "reactive.h" +#include "wire.h" + + +#include +#include + +typedef std::multimap PinListMap; + +//BEGIN class Circuit +Circuit::Circuit() +{ + m_bCanAddChanged = true; + m_pNextChanged[0] = m_pNextChanged[1] = 0l; + m_logicOutCount = 0; + m_bCanCache = false; + m_pLogicOut = 0l; + m_elementSet = new ElementSet( this, 0, 0 ); + m_cnodeCount = m_branchCount = -1; + m_prepNLCount = 0; + m_pLogicCacheBase = new LogicCacheNode; +} + +Circuit::~Circuit() +{ + delete m_elementSet; + delete m_pLogicCacheBase; + delete[] m_pLogicOut; +} + + +void Circuit::addPin( Pin *node ) +{ + if ( m_pinList.contains(node) ) return; + m_pinList.append(node); +} + +void Circuit::addElement( Element *element ) +{ + if ( m_elementList.contains(element) ) return; + m_elementList.append(element); +} + +bool Circuit::contains( Pin *node ) +{ + return m_pinList.contains(node); +} + + +// static function +int Circuit::identifyGround( PinList nodeList, int *highest ) +{ + // What this function does: + // We are given a list of pins. First, we divide them into groups of pins + // that are directly connected to each other (e.g. through wires or + // switches). Then, each group of connected pins is looked at to find the + // pin with the highest "ground priority", and this is taken to be + // the priority of the group. The highest ground priority from all the + // groups is recorded. If the highest ground priority found is the maximum, + // then all the pins in groups with this priority are marked as ground + // (their eq-id is set to -1). Otherwise, the first group of pins with the + // highest ground priority found is marked as ground, and all others are + // marked as non ground (their eq-id is set to 0). + + int temp_highest; + if (!highest) + highest = &temp_highest; + + // Now to give all the Pins ids + PinListMap eqs; + while ( !nodeList.isEmpty() ) + { + PinList associated; + PinList nodes; + Pin *node = *nodeList.begin(); + recursivePinAdd( node, &nodeList, &associated, &nodes ); + if ( nodes.size() > 0 ) + { + eqs.insert( std::make_pair( associated.size(), nodes ) ); + } + } + + + // Now, we want to look through the associated Pins, + // to find the ones with the highest "Ground Priority". Anything with a lower + // priority than Pin::gt_never will not be considered + *highest = Pin::gt_never; // The highest priority found so far + int numGround = 0; // The number of node groups found with that priority + const PinListMap::iterator eqsEnd = eqs.end(); + for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it ) + { + int highPri = Pin::gt_never; // The highest priority found in these group of nodes + const PinList::iterator send = it->second.end(); + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + if ( (*sit)->groundType() < highPri ) + highPri = (*sit)->groundType(); + } + + if ( highPri == *highest ) + numGround++; + + else if ( highPri < *highest ) + { + numGround = 1; + *highest = highPri; + } + } + + if ( *highest == Pin::gt_never ) + { + (*highest)--; + numGround=0; + } + // If there are no Always Ground nodes, then we only want to set one of the nodes as ground + else if ( *highest > Pin::gt_always ) + numGround = 1; + + + // Now, we can give the nodes their cnode ids, or tell them they are ground + bool foundGround = false; // This is only used when we don't have a Always ground node + for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it ) + { + bool ground = false; + const PinList::iterator send = it->second.end(); + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + ground |= (*sit)->groundType() <= (*highest); + } + if ( ground && (!foundGround || *highest == Pin::gt_always ) ) + { + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + (*sit)->setEqId(-1); + } + foundGround = true; + } + else + { + for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit ) + { + (*sit)->setEqId(0); + } + } + } + + return numGround; +} + + +void Circuit::init() +{ + m_branchCount = 0; + + const ElementList::iterator listEnd = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + m_branchCount += (*it)->numCBranches(); + } + + // Now to give all the Pins ids + int groundCount = 0; + PinListMap eqs; + PinList unassignedNodes = m_pinList; + while ( !unassignedNodes.isEmpty() ) + { + PinList associated; + PinList nodes; + Pin *node = *unassignedNodes.begin(); + if ( recursivePinAdd( node, &unassignedNodes, &associated, &nodes ) ) { + groundCount++; + } + if ( nodes.size() > 0 ) { + eqs.insert( std::make_pair( associated.size(), nodes ) ); + } + } + + m_cnodeCount = eqs.size() - groundCount; + + delete m_pLogicCacheBase; + m_pLogicCacheBase = 0l; + + delete m_elementSet; + m_elementSet = new ElementSet( this, m_cnodeCount, m_branchCount ); + + // Now, we can give the nodes their cnode ids, or tell them they are ground + Vector *x = m_elementSet->x(); + int i=0; + const PinListMap::iterator eqsEnd = eqs.end(); + for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it ) + { + bool foundGround = false; + + const PinList::iterator sEnd = it->second.end(); + for ( PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit ) + foundGround |= (*sit)->eqId() == -1; + + if ( foundGround ) + continue; + + bool foundEnergyStoragePin = false; + + for ( PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit ) + { + (*sit)->setEqId(i); + + bool energyStorage = false; + const ElementList elements = (*sit)->elements(); + ElementList::const_iterator elementsEnd = elements.end(); + for ( ElementList::const_iterator it = elements.begin(); it != elementsEnd; ++it ) + { + if ( !*it ) + continue; + + if ( ((*it)->type() == Element::Element_Capacitance) + || ((*it)->type() == Element::Element_Inductance) ) + { + energyStorage = true; + break; + } + } + + // A pin attached to an energy storage pin overrides one that doesn't. + // If the two pins have equal status with in this regard, we pick the + // one with the highest absolute voltage on it. + + if ( foundEnergyStoragePin && !energyStorage ) + continue; + + double v = (*sit)->voltage(); + + if ( energyStorage && !foundEnergyStoragePin ) + { + foundEnergyStoragePin = true; + (*x)[i] = v; + continue; + } + + if ( std::abs(v) > std::abs( (*x)[i] ) ) + (*x)[i] = v; + } + i++; + } + + + // And add the elements to the elementSet + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + // We don't want the element to prematurely try to do anything, + // as it doesn't know its actual cnode ids yet + (*it)->setCNodes(); + (*it)->setCBranches(); + m_elementSet->addElement(*it); + } + // And give the branch ids to the elements + i=0; + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + switch ( (*it)->numCBranches() ) + { + case 0: + break; + case 1: + (*it)->setCBranches( i ); + i += 1; + break; + case 2: + (*it)->setCBranches( i, i+1 ); + i += 2; + break; + case 3: + (*it)->setCBranches( i, i+1, i+2 ); + i += 3; + break; + default: + // What the?! + break; + } + } +} + + +void Circuit::initCache() +{ + m_elementSet->updateInfo(); + + m_bCanCache = true; + m_logicOutCount = 0; + + delete[] m_pLogicOut; + m_pLogicOut = 0l; + + delete m_pLogicCacheBase; + m_pLogicCacheBase = 0l; + + const ElementList::iterator end = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it ) + { + switch ( (*it)->type() ) + { + case Element::Element_BJT: + case Element::Element_CCCS: + case Element::Element_CCVS: + case Element::Element_CurrentSource: + case Element::Element_Diode: + case Element::Element_LogicIn: + case Element::Element_OpAmp: + case Element::Element_Resistance: + case Element::Element_VCCS: + case Element::Element_VCVS: + case Element::Element_VoltagePoint: + case Element::Element_VoltageSource: + { + break; + } + + case Element::Element_LogicOut: + { + m_logicOutCount++; + break; + } + + case Element::Element_CurrentSignal: + case Element::Element_VoltageSignal: + case Element::Element_Capacitance: + case Element::Element_Inductance: + { + m_bCanCache = false; + break; + } + } + } + + if ( !m_bCanCache ) + return; + + m_pLogicOut = new LogicOut*[m_logicOutCount]; + unsigned i = 0; + for ( ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it ) + { + if ( (*it)->type() == Element::Element_LogicOut ) + m_pLogicOut[i++] = static_cast(*it); + } + + m_pLogicCacheBase = new LogicCacheNode; +} + + +void Circuit::setCacheInvalidated() +{ + if (m_pLogicCacheBase) + { + delete m_pLogicCacheBase->high; + m_pLogicCacheBase->high = 0l; + + delete m_pLogicCacheBase->low; + m_pLogicCacheBase->low = 0l; + + delete m_pLogicCacheBase->data; + m_pLogicCacheBase->data = 0l; + } +} + + +void Circuit::cacheAndUpdate() +{ + LogicCacheNode * node = m_pLogicCacheBase; + for ( unsigned i = 0; i < m_logicOutCount; i++ ) + { + if ( m_pLogicOut[i]->outputState() ) + { + if (!node->high) + node->high = new LogicCacheNode; + + node = node->high; + } + else + { + if (!node->low) + node->low = new LogicCacheNode; + + node = node->low; + } + } + + if ( node->data ) + { + (*m_elementSet->x()) = *node->data; + m_elementSet->updateInfo(); + return; + } + + if ( m_elementSet->containsNonLinear() ) + m_elementSet->doNonLinear( 150, 1e-10, 1e-13 ); + else + m_elementSet->doLinear(true); + + node->data = new Vector( m_elementSet->x()->size() ); + *node->data = *m_elementSet->x(); +} + + +void Circuit::createMatrixMap() +{ + m_elementSet->createMatrixMap(); +} + + +bool Circuit::recursivePinAdd( Pin *node, PinList *unassignedNodes, PinList *associated, PinList *nodes ) +{ + if ( !unassignedNodes->contains(node) ) + return false; + unassignedNodes->remove(node); + + bool foundGround = node->eqId() == -1; + + const PinList circuitDependentPins = node->circuitDependentPins(); + const PinList::const_iterator dEnd = circuitDependentPins.end(); + for ( PinList::const_iterator it = circuitDependentPins.begin(); it != dEnd; ++it ) + { + if ( !associated->contains(*it) ) + associated->append(*it); + } + + nodes->append(node); + + const PinList localConnectedPins = node->localConnectedPins(); + const PinList::const_iterator end = localConnectedPins.end(); + for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it ) + foundGround |= recursivePinAdd( *it, unassignedNodes, associated, nodes ); + + return foundGround; +} + + +void Circuit::doNonLogic() +{ + if ( !m_elementSet || m_cnodeCount+m_branchCount <= 0 ) + return; + + if (m_bCanCache) + { + if ( !m_elementSet->b()->isChanged() && !m_elementSet->matrix()->isChanged() ) + return; + cacheAndUpdate(); + updateNodalVoltages(); + m_elementSet->b()->setUnchanged(); + return; + } + + stepReactive(); + if ( m_elementSet->containsNonLinear() ) + { + m_elementSet->doNonLinear( 10, 1e-9, 1e-12 ); + updateNodalVoltages(); + } + else + { + if ( m_elementSet->doLinear(true) ) + updateNodalVoltages(); + } +} + + +void Circuit::stepReactive() +{ + ElementList::iterator listEnd = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + Element * const e = *it; + if ( e && e->isReactive() ) + (static_cast(e))->time_step(); + } +} + + +void Circuit::updateNodalVoltages() +{ + CNode **_cnodes = m_elementSet->cnodes(); + + const PinList::iterator endIt = m_pinList.end(); + for ( PinList::iterator it = m_pinList.begin(); it != endIt; ++it ) + { + Pin * const node = *it; + int i = node->eqId(); + if ( i == -1 ) + node->setVoltage(0.); + else + { + const double v = _cnodes[i]->v; + node->setVoltage( std::isfinite(v)?v:0. ); + } + } +} + + +void Circuit::updateCurrents() +{ + ElementList::iterator listEnd = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) + { + (*it)->updateCurrents(); + } +} + +void Circuit::displayEquations() +{ + m_elementSet->displayEquations(); +} +//END class Circuit + + + +//BEGIN class LogicCacheNode +LogicCacheNode::LogicCacheNode() +{ + low = 0l; + high = 0l; + data = 0l; +} + + +LogicCacheNode::~LogicCacheNode() +{ + delete low; + delete high; + delete data; +} +//END class LogicCacheNode + + diff --git a/src/electronics/simulation/circuit.h b/src/electronics/simulation/circuit.h new file mode 100644 index 0000000..2455edc --- /dev/null +++ b/src/electronics/simulation/circuit.h @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef CIRCUIT_H +#define CIRCUIT_H + +#include +#include "qstringlist.h" +#include "qvaluelist.h" + +#include "elementset.h" + +class CircuitDocument; +class Wire; +class Pin; +class Element; +class LogicOut; + +typedef QValueList > PinList; +typedef QValueList ElementList; + + +class LogicCacheNode +{ + public: + LogicCacheNode(); + ~LogicCacheNode(); + + LogicCacheNode * high; + LogicCacheNode * low; + Vector * data; +}; + + +/** +Usage of this class (usually invoked from CircuitDocument): +(1) Add Wires, Pins and Elements to the class as appropriate +(2) Call init to initialize the simulation +(3) Control the simulation with step() + +This class can be considered a bridge between the gui-tainted CircuitDocument - specific +to this implementation, and the pure untainted ElementSet. Please keep it that way. + +@short Simulates a collection of components +@author David Saxton +*/ +class Circuit +{ + public: + Circuit(); + ~Circuit(); + + void addPin( Pin *node ); + void addElement( Element *element ); + + bool contains( Pin *node ); + bool containsNonLinear() const { return m_elementSet->containsNonLinear(); } + + void init(); + /** + * Called after everything else has been setup - before doNonLogic or + * doLogic are called for the first time. Preps the circuit. + */ + void initCache(); + /** + * Marks all cached results as invalidated and removes them. + */ + void setCacheInvalidated(); + /** + * Solves for non-logic elements + */ + void doNonLogic(); + /** + * Solves for logic elements (i.e just does fbSub) + */ + void doLogic() { m_elementSet->doLinear(false); } + + void displayEquations(); + void updateCurrents(); + + void createMatrixMap(); + /** + * This will identify the ground node and non-ground nodes in the given set. + * Ground will be given the eqId -1, non-ground of 0. + * @param highest The highest ground type of the groundnodes found. If no + ground nodes were found, this will be (gt_never-1). + * @returns the number of ground nodes. If all nodes are at or below the + * gt_never threshold, then this will be zero. + */ + static int identifyGround( PinList nodeList, int *highest = 0l ); + + void setNextChanged( Circuit * circuit, unsigned char chain ) { m_pNextChanged[chain] = circuit; } + Circuit * nextChanged( unsigned char chain ) const { return m_pNextChanged[chain]; } + void setCanAddChanged( bool canAdd ) { m_bCanAddChanged = canAdd; } + bool canAddChanged() const { return m_bCanAddChanged; } + + protected: + void cacheAndUpdate(); + /** + * Update the nodal voltages from those calculated in ElementSet + */ + void updateNodalVoltages(); + /** + * Step the reactive elements. + */ + void stepReactive(); + /** + * Returns true if any of the nodes are ground + */ + static bool recursivePinAdd( Pin *node, PinList *unassignedNodes, PinList *associated, PinList *nodes ); + + int m_cnodeCount; + int m_branchCount; + int m_prepNLCount; // Count until next m_elementSet->prepareNonLinear() is called + + PinList m_pinList; + ElementList m_elementList; + ElementSet *m_elementSet; + + //Stuff for caching + bool m_bCanCache; + LogicCacheNode * m_pLogicCacheBase; + unsigned m_logicOutCount; + LogicOut ** m_pLogicOut; + + bool m_bCanAddChanged; + Circuit * m_pNextChanged[2]; +}; + +#endif diff --git a/src/electronics/simulation/currentsignal.cpp b/src/electronics/simulation/currentsignal.cpp new file mode 100644 index 0000000..5e5388d --- /dev/null +++ b/src/electronics/simulation/currentsignal.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "currentsignal.h" +#include "element.h" +#include "matrix.h" + +CurrentSignal::CurrentSignal( const double delta, const double current ) + : Reactive::Reactive(delta) +{ + m_current = current; + m_oldCurrent = m_newCurrent = 0.; + m_numCNodes = 2; +} + +CurrentSignal::~CurrentSignal() +{ +} + +void CurrentSignal::setCurrent( const double i ) +{ + if ( m_oldCurrent != m_newCurrent ) add_initial_dc(); + m_newCurrent *= i/m_current; // Instead of calling step again, we can just "adjust" what the current should be + m_current = i; + add_initial_dc(); +} + + +void CurrentSignal::add_map() +{ + // We don't need a map for current signal :-) +} + + +void CurrentSignal::add_initial_dc() +{ + if ( !b_status ) + return; + + if ( m_newCurrent == m_oldCurrent ) + return; + + b_i( 0 ) -= m_newCurrent-m_oldCurrent; + b_i( 1 ) += m_newCurrent-m_oldCurrent; + + m_oldCurrent = m_newCurrent; +} + +void CurrentSignal::updateCurrents() +{ + m_cnodeI[1] = m_newCurrent; + m_cnodeI[0] = -m_newCurrent; +} + +void CurrentSignal::time_step() +{ + add_initial_dc(); // Make sure our old and new are synced + m_newCurrent = m_current*advance(); + add_initial_dc(); +} diff --git a/src/electronics/simulation/currentsignal.h b/src/electronics/simulation/currentsignal.h new file mode 100644 index 0000000..b217b79 --- /dev/null +++ b/src/electronics/simulation/currentsignal.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef CURRENTSIGNAL_H +#define CURRENTSIGNAL_H + +#include "reactive.h" +#include "elementsignal.h" + +/** +@short CurrentSignal +@author David saxton +*/ +class CurrentSignal : public Reactive, public ElementSignal +{ +public: + CurrentSignal( const double delta, const double current ); + virtual ~CurrentSignal(); + + virtual Element::Type type() const { return Element_CurrentSignal; } + void setCurrent( const double current ); + double current() { return m_current; } + virtual void time_step(); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_current; // Current + double m_oldCurrent; // Old calculated current + double m_newCurrent; // New calculated current +}; + +#endif diff --git a/src/electronics/simulation/currentsource.cpp b/src/electronics/simulation/currentsource.cpp new file mode 100644 index 0000000..675b0b7 --- /dev/null +++ b/src/electronics/simulation/currentsource.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "currentsource.h" +#include "elementset.h" +#include "matrix.h" + +CurrentSource::CurrentSource( const double current ) + : Element::Element() +{ + m_i = current; + m_numCNodes = 2; +} + + +CurrentSource::~CurrentSource() +{ +} + + +void CurrentSource::setCurrent( const double i ) +{ + if ( i == m_i ) return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Remove the old current + m_i = -m_i; + add_initial_dc(); + + m_i = i; + add_initial_dc(); +} + + +void CurrentSource::add_map() +{ + // We don't need a map for current source :-) +} + + +void CurrentSource::add_initial_dc() +{ + if (!b_status) + return; + + b_i( 0 ) -= m_i; + b_i( 1 ) += m_i; +} + + +void CurrentSource::updateCurrents() +{ + m_cnodeI[0] = -m_i; + m_cnodeI[1] = m_i; +} diff --git a/src/electronics/simulation/currentsource.h b/src/electronics/simulation/currentsource.h new file mode 100644 index 0000000..9b72e0d --- /dev/null +++ b/src/electronics/simulation/currentsource.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef CURRENTSOURCE_H +#define CURRENTSOURCE_H + +#include "element.h" + +/** +cnode n0 has current flowing otu of it, cnode n1 has current flowing into it +@author David Saxton +@short Current Source +*/ +class CurrentSource : public Element +{ +public: + CurrentSource( const double current ); + virtual ~CurrentSource(); + + virtual Type type() const { return Element_CurrentSource; } + void setCurrent( const double i ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_i; // Current +}; + +#endif diff --git a/src/electronics/simulation/diode.cpp b/src/electronics/simulation/diode.cpp new file mode 100644 index 0000000..e13d478 --- /dev/null +++ b/src/electronics/simulation/diode.cpp @@ -0,0 +1,198 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 +#include "diode.h" +#include "elementset.h" +#include "matrix.h" + +#include + + +//BEGIN class Diode Settings +DiodeSettings::DiodeSettings() +{ + reset(); +} + + +void DiodeSettings::reset() +{ + I_S = 1e-15; + N = 1.0; + V_B = 4.7; +// R = 0.001; +} +//END class Diode Settings + + + +//BEGIN class Diode +Diode::Diode() + : NonLinear() +{ + m_numCNodes = 2; + g_new = g_old = I_new = I_old = V_prev = 0.0; +} + + +Diode::~Diode() +{ +} + + +void Diode::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_unstable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_unstable, false ); + } +} + + +void Diode::add_initial_dc() +{ + g_new = g_old = I_new = I_old = V_prev = 0.0; + update_dc(); +} + + +double Diode::current() const +{ + if (!b_status) + return 0.0; + + double I; + calcIg( p_cnode[0]->v - p_cnode[1]->v, & I, 0 ); + + return I; +} + + +void Diode::updateCurrents() +{ + if (!b_status) + return; + + m_cnodeI[1] = current(); + m_cnodeI[0] = -m_cnodeI[1]; +} + + +void Diode::update_dc() +{ + if (!b_status) + return; + + calc_eq(); + + A_g( 0, 0 ) += g_new - g_old; + A_g( 1, 1 ) += g_new - g_old; + A_g( 0, 1 ) -= g_new - g_old; + A_g( 1, 0 ) -= g_new - g_old; + + b_i( 0 ) -= I_new - I_old; + b_i( 1 ) += I_new - I_old; + + g_old = g_new; + I_old = I_new; +} + + + +#ifndef MIN +# define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + + + +void Diode::calc_eq() +{ + double I_S = m_diodeSettings.I_S; + double N = m_diodeSettings.N; + double V_B = m_diodeSettings.V_B; +// double R = m_diodeSettings.R; + + double v = p_cnode[0]->v - p_cnode[1]->v; + + // adjust voltage to help convergence + double V_crit = diodeCriticalVoltage( I_S, N * V_T ); + if (V_B != 0 && v < MIN (0, -V_B + 10 * N * V_T)) + { + double V = -(v + V_B); + V = diodeVoltage( V, -(V_prev + V_B), V_T * N, V_crit ); + v = -(V + V_B); + } + else + v = diodeVoltage( v, V_prev, V_T * N, V_crit ); + + V_prev = v; + + double I_D; + calcIg( v, & I_D, & g_new ); + + I_new = I_D - (v * g_new); +} + + +void Diode::calcIg( double V, double * I_D, double * g ) const +{ + double I_S = m_diodeSettings.I_S; + double N = m_diodeSettings.N; + double V_B = m_diodeSettings.V_B; +// double R = m_diodeSettings.R; + + double gtiny = (V < - 10 * V_T * N && V_B != 0) ? I_S : 0; + + if ( V >= (-3 * N * V_T) ) + { + if ( g ) + *g = diodeConductance( V, I_S, V_T * N ) + gtiny; + *I_D = diodeCurrent( V, I_S, V_T * N ) + (gtiny * V); + } + else if ( V_B == 0 || V >= -V_B ) + { + double a = (3 * N * V_T) / (V * M_E); + a = a * a * a; + *I_D = (-I_S * (1 + a)) + (gtiny * V); + if ( g ) + *g = ((I_S * 3 * a) / V) + gtiny; + } + else + { + double a = exp( -(V_B + V) / N / V_T ); + *I_D = (-I_S * a) + (gtiny * V); + if ( g ) + *g = I_S * a / V_T / N + gtiny; + } +} + + +void Diode::setDiodeSettings( const DiodeSettings & settings ) +{ + m_diodeSettings = settings; + if (p_eSet) + p_eSet->setCacheInvalidated(); +} +//END class Diode + diff --git a/src/electronics/simulation/diode.h b/src/electronics/simulation/diode.h new file mode 100644 index 0000000..0b13946 --- /dev/null +++ b/src/electronics/simulation/diode.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef DIODE_H +#define DIODE_H + +#include "nonlinear.h" + +class DiodeSettings +{ + public: + DiodeSettings(); + void reset(); + + double I_S; ///< Diode saturation current + double N; ///< Emission coefficient + double V_B; ///< Reverse breakdown +// double R; ///< Series resistance +}; + + +/** +This simulates a diode. The simulated diode characteristics are: + +@li I_s: Diode saturation current +@li V_T: Thermal voltage = kT/4 = 25mV at 20 C +@li n: Emission coefficient, typically between 1 and 2 +@li V_RB: Reverse breakdown (large negative voltage) +@li G_RB: Reverse breakdown conductance +@li R_D: Base resistance of diode + +@short Simulates the electrical property of diode-ness +@author David Saxton +*/ +class Diode : public NonLinear +{ + public: + Diode(); + virtual ~Diode(); + + virtual void update_dc(); + virtual void add_initial_dc(); + virtual void add_map(); + virtual Element::Type type() const { return Element_Diode; } + DiodeSettings settings() const { return m_diodeSettings; } + void setDiodeSettings( const DiodeSettings & settings ); + /** + * Returns the current flowing through the diode + */ + double current() const; + + protected: + virtual void updateCurrents(); + void calc_eq(); + + void calcIg( double V, double * I, double * g ) const; + + double g_new, g_old; + double I_new, I_old; + double V_prev; + + DiodeSettings m_diodeSettings; +}; + +#endif + diff --git a/src/electronics/simulation/element.cpp b/src/electronics/simulation/element.cpp new file mode 100644 index 0000000..2411897 --- /dev/null +++ b/src/electronics/simulation/element.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "element.h" +#include "elementset.h" + +#include + +#include + +Element::Element() +{ + b_status = false; + p_A = 0l; + p_eSet = 0l; + p_b = 0l; + b_componentDeleted = false; + b_eSetDeleted = true; + + for ( int i=0; i<8; i++ ) + p_cnode[i] = 0l; + + resetCurrents(); + + for ( int i=0; i<4; i++ ) + p_cbranch[i] = 0l; + + m_numCBranches = 0; + m_numCNodes = 0; +} + +Element::~ Element() +{ +} + +void Element::resetCurrents() +{ + for ( int i=0; i<8; i++ ) + m_cnodeI[i] = 0.0; +} + +void Element::setElementSet( ElementSet *c ) +{ + assert(!b_componentDeleted); + assert(!p_eSet); + if (!c) return elementSetDeleted(); + b_eSetDeleted = false; + p_eSet = c; + p_A = p_eSet->matrix(); + p_b = p_eSet->b(); + updateStatus(); +} + +void Element::componentDeleted() +{ +// assert(!b_componentDeleted); + if (b_componentDeleted) + { + // Something strange happened here.... + } + if (b_eSetDeleted) return delete this; + b_componentDeleted = true; + b_status = false; +// kdDebug() << "Element::componentDeleted(): Setting b_status to false, this="<-1)?p_eSet->cnodes()[n0]:(n0==-1?p_eSet->ground():0l); + p_cnode[1] = (n1>-1)?p_eSet->cnodes()[n1]:(n1==-1?p_eSet->ground():0l); + p_cnode[2] = (n2>-1)?p_eSet->cnodes()[n2]:(n2==-1?p_eSet->ground():0l); + p_cnode[3] = (n3>-1)?p_eSet->cnodes()[n3]:(n3==-1?p_eSet->ground():0l); + updateStatus(); +} + +void Element::setCBranches( const int b0, const int b1, const int b2, const int b3 ) +{ + if ( !p_eSet ) + { +// cerr << "Element::setCBranches: can't set branches without circuit!"<-1)?p_eSet->cbranches()[b0]:0l; + p_cbranch[1] = (b1>-1)?p_eSet->cbranches()[b1]:0l; + p_cbranch[2] = (b2>-1)?p_eSet->cbranches()[b2]:0l; + p_cbranch[3] = (b3>-1)?p_eSet->cbranches()[b3]:0l; + updateStatus(); +} + +bool Element::updateStatus() +{ + // First, set status to false if all nodes in use are ground + b_status = false; + for ( int i=0; iisGround:false; + } + + // Set status to false if any of the nodes are not set + for ( int i=0; iisGround || p_cnode[j]->isGround ) + return m_temp; + return p_A->g( p_cnode[i]->n(), p_cnode[j]->n() ); +} + + +double & Element::A_b( uint i, uint j ) +{ + if ( p_cnode[i]->isGround ) + return m_temp; + return p_A->b( p_cnode[i]->n(), p_cbranch[j]->n() ); +} + + +double & Element::A_c( uint i, uint j ) +{ + if ( p_cnode[j]->isGround ) + return m_temp; + return p_A->c( p_cbranch[i]->n(), p_cnode[j]->n() ); +} + + +double & Element::A_d( uint i, uint j ) +{ + return p_A->d( p_cbranch[i]->n(), p_cbranch[j]->n() ); +} + + + +double & Element::b_i( uint i ) +{ + if ( p_cnode[i]->isGround ) + return m_temp; + + return (*p_b)[ p_cnode[i]->n() ]; +} + + +double & Element::b_v( uint i ) +{ + return (*p_b)[ p_eSet->cnodeCount() + p_cbranch[i]->n() ]; +} + +#endif diff --git a/src/electronics/simulation/elementset.cpp b/src/electronics/simulation/elementset.cpp new file mode 100644 index 0000000..25057c2 --- /dev/null +++ b/src/electronics/simulation/elementset.cpp @@ -0,0 +1,253 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "bjt.h" +#include "circuit.h" +#include "elementset.h" +#include "element.h" +#include "logic.h" +#include "matrix.h" +#include "nonlinear.h" +#include "vec.h" + +#include + +#include +#include +#include + +ElementSet::ElementSet( Circuit * circuit, const int n, const int m ) +{ + m_pCircuit = circuit; + m_cn = n; + m_cb = m; + p_logicIn = 0l; + p_A = new Matrix( m_cn, m_cb ); + p_b = new Vector(m_cn+m_cb); + p_x = new Vector(m_cn+m_cb); + p_x_prev = new Vector(m_cn+m_cb); + m_cbranches = new CBranch*[m_cb]; + m_cnodes = new CNode*[m_cn]; + for ( uint i=0; iset_n(i); + } + for ( uint i=0; iset_n(i); + } + m_ground = new CNode(); + m_ground->isGround = true; + b_containsNonLinear = false; +} + +ElementSet::~ElementSet() +{ + const ElementList::iterator end = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it ) + { + // Note: By calling setElementSet(0l), we might have deleted it (the Element will commit + // suicide when both the the ElementSet and Component to which it belongs have deleted + // themselves). So be very careful it you plan to do anything with the (*it) pointer + if (*it) (*it)->elementSetDeleted(); + } + for ( uint i=0; isetCacheInvalidated(); +} + + +void ElementSet::addElement( Element *e ) +{ + if ( !e || m_elementList.contains(e) ) return; + e->setElementSet(this); + m_elementList.append(e); + if ( e->isNonLinear() ) + { + b_containsNonLinear = true; + m_cnonLinearList.append( static_cast(e) ); + } +} + + +void ElementSet::createMatrixMap() +{ + p_A->createMap(); + + + // And do our logic as well... + + m_clogic = 0; + ElementList::iterator end = m_elementList.end(); + for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it ) + { + if ( dynamic_cast(*it) ) + m_clogic++; + } + + p_logicIn = new LogicIn*[m_clogic]; + int i=0; + for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it ) + { + if ( LogicIn * in = dynamic_cast(*it) ) + p_logicIn[i++] = in; + } +} + + +void ElementSet::doNonLinear( int maxIterations, double maxErrorV, double maxErrorI ) +{ +// p_x_prev->reset(); + + // And now tell the cnodes and cbranches about their new voltages & currents + updateInfo(); + + const NonLinearList::iterator end = m_cnonLinearList.end(); + + int k = 0; + do + { + // Tell the nonlinear elements to update its J, A and b from the newly calculated x + for ( NonLinearList::iterator it = m_cnonLinearList.begin(); it != end; ++it ) + (*it)->update_dc(); + + *p_x = *p_b; + p_A->performLU(); + p_A->fbSub(p_x); + updateInfo(); + + // Now, check for convergence + bool converged = true; + for ( unsigned i = 0; i < m_cn; ++i ) + { + double diff = std::abs( (*p_x_prev)[i] - (*p_x)[i] ); + if ( diff > maxErrorI ) + { + converged = false; + break; + } + } + if ( converged ) + { + for ( unsigned i = m_cn; i < m_cn+m_cb; ++i ) + { + double diff = std::abs( (*p_x_prev)[i] - (*p_x)[i] ); + if ( diff > maxErrorV ) + { + converged = false; + break; + } + } + } + + *p_x_prev = *p_x; + + if ( converged ) + break; + } + while ( ++k < maxIterations ); +} + + +bool ElementSet::doLinear( bool performLU ) +{ + if ( b_containsNonLinear || (!p_b->isChanged() && ((performLU && !p_A->isChanged()) || !performLU)) ) + return false; + + if (performLU) + p_A->performLU(); + + *p_x = *p_b; + p_A->fbSub(p_x); + updateInfo(); + p_b->setUnchanged(); + + return true; +} + + +void ElementSet::updateInfo() +{ + for ( uint i=0; iv = v; + } else { + (*p_x)[i] = 0.; + m_cnodes[i]->v = 0.; + } + } + for ( uint i=0; ii = I; + } else { + (*p_x)[i+m_cn] = 0.; + m_cbranches[i]->i = 0.; + } + } + + // Tell logic to check themselves + for ( uint i=0; icheck(); + } +} + + +void ElementSet::displayEquations() +{ + std::cout.setf(std::ios_base::fixed); + std::cout.precision(5); + std::cout.setf(std::ios_base::showpoint); + std::cout << "A x = b :"<g(i,j); +// if ( value > 0 ) cout <<"+"; +// else if ( value == 0 ) cout <<" "; + std::cout.width(10); + std::cout << value<<" "; + } + std::cout << ") ( "<<(*p_x)[i]<<" ) = ( "; + std::cout<<(*p_b)[i]<<" )"<displayLU(); +} + + diff --git a/src/electronics/simulation/elementset.h b/src/electronics/simulation/elementset.h new file mode 100644 index 0000000..c7ef7ca --- /dev/null +++ b/src/electronics/simulation/elementset.h @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ELEMENTSET_H +#define ELEMENTSET_H + +#include + +#include + +class CBranch; +class Circuit; +class CNode; +class Element; +class ElementSet; +class LogicIn; +class Matrix; +class NonLinear; +class Vector; + +typedef QValueList ElementList; +typedef QValueList NonLinearList; + +/** +Steps in simulation of a set of elements: +(1) Create this class with given number of nodes "n" and voltage sources "m" +(2) Add the various elements with addElement. +(3) Call performDC() +(4) Get the nodal voltages and voltage currents with x() +(5) Repeat steps 3 and 4 if necessary for further transient analysis. + +This class shouldn't be confused with the Circuit class, but considered a helper class to Circuit. +Circuit will handle the simulation of a set of components over time. This just finds the DC-operating +point of the circuit for a given set of elements. + +@short Handles a set of circuit elements +@author David Saxton +*/ +class ElementSet +{ +public: + /** + * Create a new circuit, with "n" nodes and "m" voltage sources. + * After creating the circuit, you must call setGround to specify + * the ground nodes, before adding any elements. + */ + ElementSet( Circuit * circuit, const int n, const int m ); + /** + * Destructor. Note that only the matrix and supporting data is deleted. + * i.e. Any elements added to the circuit will not be deleted. + */ + ~ElementSet(); + Circuit * circuit() const { return m_pCircuit; } + void addElement( Element *e ); + void setCacheInvalidated(); + /** + * Returns the matrix in use. This is created once on the creation of the ElementSet + * class, and deleted in the destructor, so the pointer returned will never change. + */ + Matrix *matrix() const { return p_A; } + /** + * Returns the vector for b (i.e. the independent currents & voltages) + */ + Vector *b() const { return p_b; } + /** + * Returns the vector for x (i.e. the currents & voltages at the branches and nodes) + */ + Vector *x() const { return p_x; } + /** + * @return if we have any nonlinear elements (e.g. diodes, tranaistors). + */ + bool containsNonLinear() const { return b_containsNonLinear; } + /** + * Solves for nonlinear elements, or just does linear if it doesn't contain + * any nonlinear. + */ + void doNonLinear( int maxIterations, double maxErrorV = 1e-9, double maxErrorI = 1e-12 ); + /** + * Solves for linear and logic elements. + * @returns true if anything changed + */ + bool doLinear( bool performLU ); + CBranch **cbranches() const { return m_cbranches; } + CNode **cnodes() const { return m_cnodes; } + CNode *ground() const { return m_ground; } + /** + * Returns the number of nodes in the circuit (excluding ground 'nodes') + */ + int cnodeCount() const { return m_cn; } + /** + * Returns the number of voltage sources in the circuit + */ + int cbranchCount() const { return m_cb; } + + void createMatrixMap(); + /** + * Displays the matrix equations Ax=b and J(dx)=-r + */ + void displayEquations(); + /** + * Update the nodal voltages and branch currents from the x vector + */ + void updateInfo(); + +private: + Matrix *p_A; + Vector *p_x; + Vector *p_x_prev; + Vector *p_b; + uint m_cn; + uint m_cb; + ElementList m_elementList; + NonLinearList m_cnonLinearList; + CBranch **m_cbranches; // Pointer to an array of cbranches + CNode **m_cnodes; // Pointer to an array of cnodes + CNode *m_ground; + uint m_clogic; + LogicIn **p_logicIn; + bool b_containsNonLinear; + Circuit * m_pCircuit; +}; + +#endif + diff --git a/src/electronics/simulation/elementsignal.cpp b/src/electronics/simulation/elementsignal.cpp new file mode 100644 index 0000000..31d7d78 --- /dev/null +++ b/src/electronics/simulation/elementsignal.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "elementsignal.h" +#include + +ElementSignal::ElementSignal() +{ + m_type = ElementSignal::st_sinusoidal; + m_time = 0.; + m_frequency = 0.; +} + +ElementSignal::~ElementSignal() +{ +} + +void ElementSignal::setStep( double delta, Type type, double frequency ) +{ + m_type = type; + m_delta = delta; + m_frequency = frequency; + m_omega = 6.283185307179586*m_frequency; + m_time = 1./(4.*m_frequency); +} + +double ElementSignal::advance() +{ + m_time += m_delta; + if ( m_time >= 1./m_frequency ) m_time -= 1./m_frequency; + + switch (m_type) + { + case ElementSignal::st_sawtooth: + { + // TODO Sawtooth signal + return 0.; + } + case ElementSignal::st_square: + { + return (sin(m_time*m_omega)>=0)?1:-1; + } + case ElementSignal::st_triangular: + { + // TODO Triangular signal + return 0.; + } + case ElementSignal::st_sinusoidal: + default: + { + return sin(m_time*m_omega); + } + } +} + + + diff --git a/src/electronics/simulation/elementsignal.h b/src/electronics/simulation/elementsignal.h new file mode 100644 index 0000000..c26bea1 --- /dev/null +++ b/src/electronics/simulation/elementsignal.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ELEMENTSIGNAL_H +#define ELEMENTSIGNAL_H + +/** +@short Provides different signals +@author David Saxton +*/ +class ElementSignal +{ +public: + enum Type + { + st_sinusoidal, + st_square, + st_sawtooth, + st_triangular + }; + ElementSignal(); + ~ElementSignal(); + + void setStep( double delta, Type type, double frequency ); + /** + * Advances the timer, returns amplitude (between -1 and 1) + */ + double advance(); + +protected: + Type m_type; + double m_time; + double m_frequency; + double m_delta; + double m_omega; // Used for sinusoidal signal +}; + +#endif diff --git a/src/electronics/simulation/inductance.cpp b/src/electronics/simulation/inductance.cpp new file mode 100644 index 0000000..22c5f9e --- /dev/null +++ b/src/electronics/simulation/inductance.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + * 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 "elementset.h" +#include "inductance.h" +#include "matrix.h" + +Inductance::Inductance( double inductance, double delta ) + : Reactive(delta) +{ + m_inductance = inductance; + r_eq_old = v_eq_old = 0.0; + m_numCNodes = 2; + m_numCBranches = 1; + setMethod( Inductance::m_euler ); +} + + +Inductance::~Inductance() +{ +} + + +void Inductance::setInductance( double i ) +{ + m_inductance = i; +} + + +void Inductance::add_initial_dc() +{ + A_c( 0, 0 ) = 1; + A_b( 0, 0 ) = 1; + A_c( 0, 1 ) = -1; + A_b( 1, 0 ) = -1; + + // The adding of r_eg and v_eq will be done for us by time_step. + // So for now, just reset the constants used. + r_eq_old = v_eq_old = 0.0; +} + + +void Inductance::updateCurrents() +{ + if (!b_status) + return; + m_cnodeI[0] = p_cbranch[0]->i; + m_cnodeI[1] = -m_cnodeI[0]; +} + + +void Inductance::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + } + + p_A->setUse_d( p_cbranch[0]->n(), p_cbranch[0]->n(), Map::et_unstable, false ); +} + + +void Inductance::time_step() +{ + if (!b_status) return; + + double i = p_cbranch[0]->i; + double v_eq_new = 0.0, r_eq_new = 0.0; + + if ( m_method == Inductance::m_euler ) + { + r_eq_new = m_inductance/m_delta; + v_eq_new = -i*r_eq_new; + } + else if ( m_method == Inductance::m_trap ) { + // TODO Implement + test trapezoidal method + r_eq_new = 2.0*m_inductance/m_delta; + } + + if ( r_eq_old != r_eq_new ) + { + A_d( 0, 0 ) -= r_eq_new - r_eq_old; + } + + if ( v_eq_new != v_eq_old ) + { + b_v( 0 ) += v_eq_new - v_eq_old; + } + + r_eq_old = r_eq_new; + v_eq_old = v_eq_new; +} + + +bool Inductance::updateStatus() +{ + b_status = Reactive::updateStatus(); + if ( m_method == Inductance::m_none ) + b_status = false; + return b_status; +} + + +void Inductance::setMethod( Method m ) +{ + m_method = m; + updateStatus(); +} + diff --git a/src/electronics/simulation/inductance.h b/src/electronics/simulation/inductance.h new file mode 100644 index 0000000..46ccb09 --- /dev/null +++ b/src/electronics/simulation/inductance.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef INDUCTANCE_H +#define INDUCTANCE_H + +#include "reactive.h" + +/** + +@author David Saxton +*/ +class Inductance : public Reactive +{ + public: + enum Method + { + m_none, // None + m_euler, // Backward Euler + m_trap // Trapezoidal (currently unimplemented) + }; + Inductance( double capacitance, double delta ); + virtual ~Inductance(); + + virtual Type type() const { return Element_Inductance; } + /** + * Set the stepping use for numerical integration of inductance, and the + * interval between successive updates. + */ + void setMethod( Method m ); + virtual void time_step(); + virtual void add_initial_dc(); + void setInductance( double i ); + virtual void add_map(); + + protected: + virtual void updateCurrents(); + virtual bool updateStatus(); + + private: + double m_inductance; // Inductance + Method m_method; // Method of integration + + double r_eq_old; + double v_eq_old; +}; + +#endif diff --git a/src/electronics/simulation/logic.cpp b/src/electronics/simulation/logic.cpp new file mode 100644 index 0000000..031dd2e --- /dev/null +++ b/src/electronics/simulation/logic.cpp @@ -0,0 +1,319 @@ +/*************************************************************************** + * Copyright (C) 2003-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 +#include "circuit.h" +#include "elementset.h" +#include "logic.h" +#include "matrix.h" +#include "simulator.h" +#include "src/core/ktlconfig.h" + +LogicIn::LogicIn( LogicConfig config ) + : Element::Element() +{ + m_config = config; + m_pCallbackFunction = 0l; + m_numCNodes = 1; + m_bLastState = false; + m_pNextLogic = 0l; + setLogic(getConfig()); +} + +LogicIn::~LogicIn() +{ + Simulator::self()->removeLogicInReferences(this); +} + + +void LogicIn::setCallback( CallbackClass * object, CallbackPtr func ) +{ + m_pCallbackFunction = func; + m_pCallbackObject = object; +} + + +void LogicIn::check() +{ + if (!b_status) + return; + + bool newState; + if (m_bLastState) + { + // Was high, will still be high unless voltage is less than falling trigger + newState = p_cnode[0]->v > m_config.fallingTrigger; + } + else + { + // Was low, will still be low unless voltage is more than rising trigger + newState = p_cnode[0]->v > m_config.risingTrigger; + } + + if ( m_pCallbackFunction && (newState != m_bLastState) ) + { + m_bLastState = newState; + (m_pCallbackObject->*m_pCallbackFunction)(newState); + } + m_bLastState = newState; +} + + +void LogicIn::setLogic( LogicConfig config ) +{ + m_config = config; + check(); +} + + +void LogicIn::setElementSet( ElementSet *c ) +{ + if (c) + m_pNextLogic = 0l; + else + m_cnodeI[0] = 0.; + + Element::setElementSet(c); +} + + +void LogicIn::add_initial_dc() +{ +} + + +void LogicIn::updateCurrents() +{ +} + + +LogicConfig LogicIn::getConfig() +{ + LogicConfig c; + c.risingTrigger = KTLConfig::logicRisingTrigger(); + c.fallingTrigger = KTLConfig::logicFallingTrigger(); + c.output = KTLConfig::logicOutputHigh(); + c.highImpedance = KTLConfig::logicOutputHighImpedance(); + c.lowImpedance = KTLConfig::logicOutputLowImpedance(); + return c; +} + + +LogicOut::LogicOut( LogicConfig config, bool _high ) + : LogicIn(config) +{ + m_bCanAddChanged = true; + m_bOutputHighConductanceConst = false; + m_bOutputLowConductanceConst = false; + m_bOutputHighVoltageConst = false; + m_pNextChanged[0] = m_pNextChanged[1] = 0l; + m_pSimulator = 0l; + m_bUseLogicChain = false; + b_state = false; + m_numCNodes = 1; + m_vHigh = m_gHigh = m_gLow = 0.0; + m_old_g_out = m_g_out = 0.0; + m_old_v_out = m_v_out = 0.0; + setHigh(_high); + + // Although we already call this function in LogicIn's constructor, our + // virtual function will not have got called, so we have to call it again. + setLogic(getConfig()); +} + +LogicOut::~LogicOut() +{ + if (!m_pSimulator) + m_pSimulator = Simulator::self(); + + // Note that although this function will get called in the destructor of + // LogicIn, we must call it here as well as it needs to be called before + // removeLogicOutReferences(this) is called. + m_pSimulator->removeLogicInReferences(this); + + m_pSimulator->removeLogicOutReferences(this); +} + + +void LogicOut::setUseLogicChain( bool use ) +{ + if (!m_pSimulator) + m_pSimulator = Simulator::self(); + + m_bUseLogicChain = use; + if (use) + setElementSet(0l); +} + + +void LogicOut::setElementSet( ElementSet *c ) +{ + if (!m_pSimulator) + m_pSimulator = Simulator::self(); + + if (c) + { + m_bUseLogicChain = false; + m_pNextChanged[0] = m_pNextChanged[1] = 0l; + } + + // NOTE Make sure that the next two lines are the same as those in setHigh and setLogic + m_g_out = b_state ? m_gHigh : m_gLow; + m_v_out = b_state ? m_vHigh : 0.0; + + LogicIn::setElementSet(c); +} + + +void LogicOut::setOutputHighConductance( double g ) +{ + m_bOutputHighConductanceConst = true; + if ( g == m_gHigh ) + return; + m_gHigh = g; + configChanged(); +} + + +void LogicOut::setOutputLowConductance( double g ) +{ + m_bOutputLowConductanceConst = true; + if ( g == m_gLow ) + return; + m_gLow = g; + configChanged(); +} + + +void LogicOut::setOutputHighVoltage( double v ) +{ + m_bOutputHighVoltageConst = true; + if ( v == m_vHigh ) + return; + m_vHigh = v; + configChanged(); +} + + +void LogicOut::setLogic( LogicConfig config ) +{ + m_config = config; + + if (!m_bOutputHighConductanceConst) + m_gHigh = 1.0/config.highImpedance; + + if (!m_bOutputLowConductanceConst) + m_gLow = (config.lowImpedance == 0.0) ? 0.0 : 1.0/config.lowImpedance; + + if (!m_bOutputHighVoltageConst) + m_vHigh = config.output; + + configChanged(); +} + + +void LogicOut::configChanged() +{ + if (m_bUseLogicChain) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Re-add the DC stuff using the new values + + m_old_g_out = m_g_out; + m_old_v_out = m_v_out; + + // NOTE Make sure that the next two lines are the same as those in setElementSet and setHigh + m_g_out = b_state ? m_gHigh : m_gLow; + m_v_out = b_state ? m_vHigh : 0.0; + + add_initial_dc(); + + m_old_g_out = 0.; + m_old_v_out = 0.; + + check(); +} + + +void LogicOut::add_map() +{ + if (!b_status) return; + + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_variable, false ); +} + + +void LogicOut::add_initial_dc() +{ + if (!b_status) + return; + + A_g( 0, 0 ) += m_g_out-m_old_g_out; + b_i( 0 ) += m_g_out*m_v_out-m_old_g_out*m_old_v_out; +} + +void LogicOut::updateCurrents() +{ + if (m_bUseLogicChain) + { + m_cnodeI[0] = 0.; + return; + } + if (!b_status) { + return; + } + m_cnodeI[0] = (p_cnode[0]->v-m_v_out)*m_g_out; +} + +void LogicOut::setHigh( bool high ) +{ + if ( high == b_state ) + return; + + if (m_bUseLogicChain) + { + b_state = high; + + for ( LogicIn * logic = this; logic; logic = logic->nextLogic() ) + logic->setLastState(high); + + if (m_bCanAddChanged) + { + m_pSimulator->addChangedLogic(this); + m_bCanAddChanged = false; + } + + return; + } + + m_old_g_out = m_g_out; + m_old_v_out = m_v_out; + + // NOTE Make sure that the next two lines are the same as those in setElementSet and setLogic + m_g_out = high ? m_gHigh : m_gLow; + m_v_out = high ? m_vHigh : 0.0; + + add_initial_dc(); + + m_old_g_out = 0.; + m_old_v_out = 0.; + + b_state = high; + + if ( p_eSet && p_eSet->circuit()->canAddChanged() ) + { + m_pSimulator->addChangedCircuit( p_eSet->circuit() ); + p_eSet->circuit()->setCanAddChanged(false); + } +} + diff --git a/src/electronics/simulation/logic.h b/src/electronics/simulation/logic.h new file mode 100644 index 0000000..be8374f --- /dev/null +++ b/src/electronics/simulation/logic.h @@ -0,0 +1,211 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef LOGIC_H +#define LOGIC_H + +#include "element.h" + +#include +#include + +class Component; +class Pin; +class Simulator; + +typedef QValueList > PinList; + +typedef struct +{ + float risingTrigger; // Trigger on rising edge + float fallingTrigger; // Trigger on falling edge + float output; // Output voltage + float highImpedance; // Output impedance when high + float lowImpedance; // Output impedance when low +} LogicConfig; + +class CallbackClass {}; +typedef void(CallbackClass::*CallbackPtr)( bool isHigh ); + +/** +Use this class for Logic Inputs - this will have infinite impedance. +Use isHigh() will return whether the voltage level at the pin +is high than the predetermined voltage threshold, and setHigh() will make the +output high/low, also according to the predetermined logic type / voltages. + +@short Boolean Logic input +*/ +class LogicIn : public Element +{ + public: + LogicIn( LogicConfig config ); + virtual ~LogicIn(); + + virtual Type type() const { return Element_LogicIn; } + virtual void setElementSet( ElementSet *c ); + + /** + * Set logic values from the LogicConfig. + */ + virtual void setLogic( LogicConfig config ); + /** + * Check if the input state has changed, to see if we need to callback. + */ + void check(); + /** + * Returns whether the pin is 'high', as defined for the logic type + * Note: this is defined as the voltage on the pin, as opposed to what the + * state was set to (the two are not necessarily the same). + */ + bool isHigh() const { return m_bLastState; } + /** + * When the logic state on this LogicIn changes, the function passed in this + * function will be called. At most one Callback can be added per LogicIn. + */ + void setCallback( CallbackClass * object, CallbackPtr func ); + /** + * Reads the LogicConfig values in from KTLConfig, and returns them in a + * nice object form. + */ + static LogicConfig getConfig(); + /** + * If this belongs to a logic chain, then this will be called from the chain. + */ + void setLastState( bool state ) { m_bLastState = state; } + /** + * Returns a pointer to the next LogicIn in the chain. + */ + LogicIn * nextLogic() const { return m_pNextLogic; } + /** + * Sets the next LogicIn in the chain. + */ + void setNextLogic( LogicIn * next ) { m_pNextLogic = next; } + /** + * Calls the callback function, if there is one. + */ + void callCallback() + { + if (m_pCallbackFunction) + (m_pCallbackObject->*m_pCallbackFunction)(m_bLastState); + } + + protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + + CallbackPtr m_pCallbackFunction; + CallbackClass * m_pCallbackObject; + bool m_bLastState; + LogicIn * m_pNextLogic; + LogicConfig m_config; +}; + + +/** +@short Logic output/input +*/ +class LogicOut : public LogicIn +{ + public: + LogicOut( LogicConfig config, bool _high ); + virtual ~LogicOut(); + + virtual void setLogic( LogicConfig config ); + virtual void setElementSet( ElementSet *c ); + virtual void add_map(); + virtual Type type() const { return Element_LogicOut; } + + /** + * Call this function to override the logic-high output impedance as set by + * the user. Once set, the impedance will not be changed by the user + * updating the config; only by subsequent calls to this function. + */ + void setOutputHighConductance( double g ); + /** + * Call this function to override the logic-low output impedance as set by + * the user. Once set, the impedance will not be changed by the user + * updating the config; only by subsequent calls to this function. + */ + void setOutputLowConductance( double g ); + /** + * Call this function to override the logic out voltage as set by the + * user. Once set, the impedance will not be changed by the user + * updating the config; only by subsequent calls to this function. + */ + void setOutputHighVoltage( double v ); + /** + * Returns the voltage that this will output when high. + */ + double outputHighVoltage() const { return m_vHigh; } + /** + * Sets the pin to be high/low + */ + void setHigh( bool high ); + /** + * @returns the state that this is outputting (regardless of voltage level on logic) + */ + bool outputState() const { return b_state; } + /** + * Set whether or not this LogicOut is the head of a LogicChain (controls + * itself and a bunch of LogicIns). + */ + void setUseLogicChain( bool use ); + /** + * When a LogicOut configured as the start of a LogicChain changes start, it + * appends a pointer to itself to the list of change LogicOut, starting from + * the Simulator. This functions enables appending the next changed LogicOut + * to this one. + */ + void setNextChanged( LogicOut * logicOut, unsigned char chain ) { m_pNextChanged[chain] = logicOut; } + /** + * To avoid a pointer to this LogicOut being added twice in one + * iteration due to the state changing twice, this LogicOut sets an + * added flag to true after adding it to the list of changed. The flag + * must be reset to false with this function (done by Simulator). + */ + void setCanAddChanged( bool canAdd ) { m_bCanAddChanged = canAdd; } + /** + * Returns the next LogicOut that has changed, when configured as the start + * of a LogicChain. + * @see setNextChanged + */ + LogicOut * nextChanged( unsigned char chain ) const { return m_pNextChanged[chain]; } + PinList pinList; + PinList::iterator pinListBegin; + PinList::iterator pinListEnd; + + protected: + void configChanged(); + virtual void updateCurrents(); + virtual void add_initial_dc(); + + // Pre-initalized levels from config + double m_gHigh; + double m_gLow; + double m_vHigh; + + // Whether to use the user-defined logic values + bool m_bOutputHighConductanceConst; + bool m_bOutputLowConductanceConst; + bool m_bOutputHighVoltageConst; + + double m_g_out; + double m_v_out; + double m_old_g_out; + double m_old_v_out; + bool b_state; + bool m_bCanAddChanged; + LogicOut * m_pNextChanged[2]; + Simulator * m_pSimulator; + bool m_bUseLogicChain; +}; + +#endif + diff --git a/src/electronics/simulation/matrix.cpp b/src/electronics/simulation/matrix.cpp new file mode 100644 index 0000000..fb1248f --- /dev/null +++ b/src/electronics/simulation/matrix.cpp @@ -0,0 +1,546 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "matrix.h" + +#include + +#include + +#include +#include +#include + +/// Minimum value before an entry is deemed "zero" +const double epsilon = 1e-50; + +Matrix::Matrix( uint n, uint m ) +{ + m_n = n; + m_m = m; + m_size = m_n+m_m; + + m_mat = new matrix(m_size); + m_lu = new matrix(m_size); + m_y = new double[m_size]; + m_inMap = new int[m_size]; +// m_outMap = new int[m_size]; + m_map = new Map(m_size); + zero(); +} + + +Matrix::~Matrix() +{ + delete m_map; + delete m_mat; + delete m_lu; + delete [] m_y; + delete [] m_inMap; +// delete [] m_outMap; +} + + +void Matrix::zero() +{ + for ( uint i=0; isetUse( i, j, type, big ); +} + + +void Matrix::createMap() +{ + int newMap[m_size]; + m_map->createMap(newMap); + for ( uint i=0; iswapRows( a, b ); + + const int old = m_inMap[a]; + m_inMap[a] = m_inMap[b]; + m_inMap[b] = old; + + max_k = 0; +} + + +/*void Matrix::genOutMap() +{ + for ( uint i=0; im(i,j); + } + } + + max_k = 0; +} + +void Matrix::operator+=( Matrix *const m ) +{ + for ( uint _i=0; _im(i,j); + } + } + + max_k = 0; +} + +void Matrix::performLU() +{ +// max_k = 0; + uint n = m_size; + if ( n == 0 ) return; + + // Copy the affected segment to LU + for ( uint i=max_k; i 1e-12 ) + { + for ( uint j=std::max(k,max_k)+1; j=0; i-- ) + { + double sum = 0; + for ( uint j=i+1; jreset(); + for ( uint _i=0; _i 0 && (*m_mat)[i][j] >= 0 ) kdDebug() << "+"; + kdDebug() << (*m_mat)[i][j] << "("< 0 && (*m_lu)[i][j] >= 0 ) std::cout << "+"; + std::cout << (*m_lu)[i][j] << "("<"<"<= 0 && map[i] < int(m_size) ); + } + + // Ignore this, for now: + + // Now, we want to order the matrix, with the following priorities: + // (1) How often values change + // (2) How few values there are + // (3) How large the values are + // For each value in the column, +} + + +bool Map::typeCmp( const uint t1, const uint t2 ) +{ + if (!t2) return true; + if (!t1) return false; + + int t1_score = 1; + if ( t1 | Map::et_constant ) t1_score += 64; + else if ( t1 | Map::et_stable ) t1_score += 16; + else if ( t1 | Map::et_variable ) t1_score += 4; + + int t2_score = 1; + if ( t2 | Map::et_constant ) t2_score += 64; + else if ( t2 | Map::et_stable ) t2_score += 16; + else if ( t2 | Map::et_variable ) t2_score += 4; + + if ( t1 | Map::et_big ) t1_score *= 2; + if ( t2 | Map::et_big ) t2_score *= 2; + + return ( t1_score >= t2_score ); +} + + +Matrix22::Matrix22() +{ + reset(); +} + +bool Matrix22::solve() +{ + const double old_x1 = m_x1; + const double old_x2 = m_x2; + + const bool e11 = std::abs((m_a11)) + +class Map; + +typedef std::vector > ETMap; + +/** +@short Handles row-wise permutation of matrixes +*/ +class Map +{ +public: + enum e_type + { + et_none = 0x0, // Default value, none + et_constant = 0x1, // Never changes value in lifetime of matrix + et_stable = 0x2, // Value changes occasionally, e.g. user changing resistance value + et_variable = 0x3, // Rate of changing is unknown, probably average - e.g. logic + et_unstable = 0x4, // Value changes practically every call of performLU + et_big = 0x8 // Ignore this :-) It is used to OR with one of the others, but it should only ever be accessed by the class + }; + Map( const uint size ); + ~Map(); + + void setUse( const uint i, const uint j, Map::e_type type, bool big ); + /** + * Generates an optimal permutation, returned in the given array + */ + void createMap( int *map ); + /** + * Resets the info to a blank pattern + */ + void reset(); + +protected: + /** + * Compares two "types", returning true if t1 >= t2, else false + */ + bool typeCmp( const uint t1, const uint t2 ); + +private: + ETMap *m_map; + uint m_size; +}; + +/** +This class performs matrix storage, lu decomposition, forward and backward +substitution, and a few other useful operations. Steps in using class: +(1) Create an instance of this class with the correct size +(2) Define the matrix pattern as neccessary: + (1) Call zero (unnecessary after initial ceration) to reset the pattern + & matrix + (2) Call setUse to set the use of each element in the matrix + (3) Call createMap to generate the row-wise permutation mapping for use + in partial pivoting +(3) Add the values to the matrix +(4) Call performLU, and get the results with fbSub +(5) Repeat 2, 3, 4 or 5 as necessary. +@todo We need to allow createMap to work while the matrix has already been initalised +@short Matrix manipulation class tailored for circuit equations +@author David Saxton +*/ +class Matrix +{ +public: + /** + * Creates a size x size square matrix m, with all values zero, + * and a right side vector x of size m+n + */ + Matrix( uint n, uint m ); + ~Matrix(); + /** + * Sets all elements to zero + */ + void zero(); + /** + * Sets the type of (matrix-) element at the position i, j. + * @param type Describes how often the value changes + * @param big Set this true if the value is likely to be >= 1, else false + */ + void setUse( const uint i, const uint j, Map::e_type type, bool big ); + void setUse_b( const uint i, const uint j, Map::e_type type, bool big ) + { + setUse( i, j+m_n, type, big ); + } + void setUse_c( const uint i, const uint j, Map::e_type type, bool big ) + { + setUse( i+m_n, j, type, big ); + } + void setUse_d( const uint i, const uint j, Map::e_type type, bool big ) + { + setUse( i+m_n, j+m_n, type, big ); + } + /** + * Generates the row-wise permutation mapping from the values set by setUse + */ + void createMap(); + /** + * Returns true if the matrix is changed since last calling performLU() + * - i.e. if we do need to call performLU again. + */ + inline bool isChanged() const { return max_k < m_size; } + /** + * Performs LU decomposition. Going along the rows, + * the value of the decomposed LU matrix depends only on + * the previous values. + */ + void performLU(); + /** + * Applies the right side vector (x) to the decomposed matrix, + * with the solution returned in x. + */ + void fbSub( Vector* x ); + /** + * Prints the matrix to stdout + */ + void displayMatrix(); + /** + * Prints the LU-decomposed matrix to stdout + */ + void displayLU(); + /** + * Sets the element matrix at row i, col j to value x + */ + double& g( uint i, uint j ) + { + i = m_inMap[i]; + if ( i0 ) max_k--; + + return (*m_mat)[i][j]; + } + double& b( uint i, uint j ) { return g( i, j+m_n ); } + double& c( uint i, uint j ) { return g( i+m_n, j ); } + double& d( uint i, uint j ) { return g( i+m_n, j+m_n ); } + const double g( uint i, uint j ) const { return (*m_mat)[m_inMap[i]][j]; } + const double b( uint i, uint j ) const { return g( i, j+m_n ); } + const double c( uint i, uint j ) const { return g( i+m_n, j ); } + const double d( uint i, uint j ) const { return g( i+m_n, j+m_n ); } + /** + * Returns the value of matrix at row i, col j. + */ + const double m( uint i, uint j ) const + { + return (*m_mat)[m_inMap[i]][j]; + } + /** + * Multiplies this matrix by the Vector rhs, and places the result + * in the vector pointed to by result. Will fail if wrong size. + */ + void multiply( Vector *rhs, Vector *result ); + /** + * Sets the values of this matrix to that of the given matrix + */ + void operator=( Matrix *const m ); + /** + * Adds the values of the given matrix to this matrix + */ + void operator+=( Matrix *const m ); + +private: + /** + * Swaps around the rows in the (a) the matrix; and (b) the mappings + */ + void swapRows( const uint a, const uint b ); + +// // Generates m_outMap from m_inMap +// void genOutMap(); + + uint m_n; + uint m_m; + uint m_size; + uint max_k; + + int *m_inMap; // Rowwise permutation mapping from external reference to internal storage +// int *m_outMap; // Opposite of m_inMap + + matrix *m_mat; + matrix *m_lu; + double *m_y; // Avoids recreating it lots of times + Map *m_map; +}; + + +/** +This class provides a very simple, lightweight, 2x2 matrix solver. +It's fast and reliable. Set the values for the entries of A and b: + +A x = b + +call solve() (which returns true if successful - i.e. exactly one solution to the +matrix), and get the values of x with the appropriate functions. + +@short 2x2 Matrix +@author David Saxton +*/ +class Matrix22 +{ +public: + Matrix22(); + + double &a11() { return m_a11; } + double &a12() { return m_a12; } + double &a21() { return m_a21; } + double &a22() { return m_a22; } + + double &b1() { return m_b1; } + double &b2() { return m_b2; } + + /** + * Solve the matrix. Returns true if successful (i.e. non-singular), else + * false. Get the solution with x1() and x2(). + */ + bool solve(); + /** + * Resets all entries to zero + */ + void reset(); + + double x1() const { return m_x1; } + double x2() const { return m_x2; } + +private: + double m_a11, m_a12, m_a21, m_a22; + double m_b1, m_b2; + double m_x1, m_x2; +}; + + +#endif diff --git a/src/electronics/simulation/nonlinear.cpp b/src/electronics/simulation/nonlinear.cpp new file mode 100644 index 0000000..c975f16 --- /dev/null +++ b/src/electronics/simulation/nonlinear.cpp @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2003-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 "matrix.h" +#include "nonlinear.h" + +#include +using namespace std; + +const double KTL_MAX_DOUBLE = 1.7976931348623157e+308; ///< 7fefffff ffffffff +const int KTL_MAX_EXPONENT = int( log( KTL_MAX_DOUBLE ) ); + + +NonLinear::NonLinear() + : Element() +{ +} + + +#ifndef MIN +# define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + + +// The function computes the exponential pn-junction current. +double NonLinear::diodeCurrent( double v, double I_S, double Vte ) const +{ + return I_S * (exp( MIN( v / Vte, KTL_MAX_EXPONENT ) ) - 1); +} + + + +double NonLinear::diodeConductance( double v, double I_S, double Vte ) const +{ + return I_S * exp( MIN( v / Vte, KTL_MAX_EXPONENT ) ) / Vte; +} + + + +double NonLinear::diodeVoltage( double V, double V_prev, double V_T, double Vcrit ) const +{ + if ( V > Vcrit && fabs( V - V_prev ) > 2 * V_T ) + { + if ( V_prev > 0 ) + { + double arg = (V - V_prev) / V_T; + if (arg > 0) + V = V_prev + V_T * (2 + log( arg - 2 )); + else + V = V_prev - V_T * (2 + log( 2 - arg )); + } + else + V = (V_prev < 0) ? (V_T * log (V / V_T)) : Vcrit; + } + else + { + if ( V < 0 ) + { + double arg = (V_prev > 0) ? (-1 - V_prev) : (2 * V_prev - 1); + if (V < arg) + V = arg; + } + } + return V; +} + + +double NonLinear::diodeCriticalVoltage( double I_S, double V_Te ) const +{ + return V_Te * log( V_Te / M_SQRT2 / I_S ); +} + + +void NonLinear::diodeJunction( double V, double I_S, double V_Te, double * I, double * g ) const +{ + if (V < -3 * V_Te) + { + double a = 3 * V_Te / (V * M_E); + a = a * a * a; + *I = -I_S * (1 + a); + *g = +I_S * 3 * a / V; + } + else + { + double e = exp( MIN( V / V_Te, KTL_MAX_EXPONENT ) ); + *I = I_S * (e - 1); + *g = I_S * e / V_Te; + } +} + diff --git a/src/electronics/simulation/nonlinear.h b/src/electronics/simulation/nonlinear.h new file mode 100644 index 0000000..422f3a4 --- /dev/null +++ b/src/electronics/simulation/nonlinear.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2003-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. * + ***************************************************************************/ + +#ifndef NONLINEAR_H +#define NONLINEAR_H + +#include "element.h" + +/** +@short Represents a non-linear circuit element (such as a diode) +@author David Saxton +*/ +class NonLinear : public Element +{ + public: + NonLinear(); + + virtual bool isNonLinear() { return true; } + /** + * Newton-Raphson iteration: Update equation system. + */ + virtual void update_dc() = 0; + + protected: + double diodeCurrent( double v, double I_S, double Vte ) const; + /** + * Conductance of the diode - the derivative of Schockley's + * approximation. + */ + double diodeConductance( double v, double I_S, double Vte ) const; + /** + * Limits the diode voltage to prevent divergence in the nonlinear + * iterations. + */ + double diodeVoltage( double v, double V_prev, double Vt, double V_crit ) const; + void diodeJunction( double v, double I_S, double Vte, double * I, double * g ) const; + + double diodeCriticalVoltage( double I_S, double Vte ) const; +}; + +#endif diff --git a/src/electronics/simulation/opamp.cpp b/src/electronics/simulation/opamp.cpp new file mode 100644 index 0000000..45fbf02 --- /dev/null +++ b/src/electronics/simulation/opamp.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * 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 "elementset.h" +#include "matrix.h" +#include "opamp.h" + +OpAmp::OpAmp() + : Element::Element() +{ + m_numCBranches = 1; + m_numCNodes = 3; +} + + +OpAmp::~OpAmp() +{ +} + + +void OpAmp::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + // Non-inverting input + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[2]->isGround ) + { + // Inverting input + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + // Output + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + } +} + + +void OpAmp::add_initial_dc() +{ + if (!b_status) + return; + + // Non-inverting input + A_c( 0, 0 ) = 1; + + // Inverting input + A_c( 0, 2 ) = -1; + + // Output + A_b( 1, 0 ) = 1; +} + + +void OpAmp::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = m_cnodeI[2] = 0.0; + m_cnodeI[1] = p_cbranch[0]->i; +} + + + diff --git a/src/electronics/simulation/opamp.h b/src/electronics/simulation/opamp.h new file mode 100644 index 0000000..22fe843 --- /dev/null +++ b/src/electronics/simulation/opamp.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef OPAMP_H +#define OPAMP_H + +#include + +/** +node 0: non-inverting input +node 1: output +node 2: inverting input +@author David Saxton +*/ +class OpAmp : public Element +{ + public: + OpAmp(); + virtual ~OpAmp(); + + virtual Type type() const { return Element_OpAmp; } + virtual void add_map(); + + protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); +}; + +#endif diff --git a/src/electronics/simulation/reactive.cpp b/src/electronics/simulation/reactive.cpp new file mode 100644 index 0000000..83fcfd4 --- /dev/null +++ b/src/electronics/simulation/reactive.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "reactive.h" + +Reactive::Reactive( const double delta ) + : Element() +{ + m_delta = delta; +} + + +Reactive::~Reactive() +{ +} + + +void Reactive::setDelta( double delta ) +{ + m_delta = delta; + updateStatus(); +} + + +bool Reactive::updateStatus() +{ + return Element::updateStatus(); +} diff --git a/src/electronics/simulation/reactive.h b/src/electronics/simulation/reactive.h new file mode 100644 index 0000000..1142b34 --- /dev/null +++ b/src/electronics/simulation/reactive.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef REACTIVE_H +#define REACTIVE_H + +#include "element.h" + +/** +@short Represents a reactive element (such as a capacitor) +@author David Saxton +*/ +class Reactive : public Element +{ +public: + Reactive( const double delta ); + virtual ~Reactive(); + + virtual bool isReactive() { return true; } + /** + * Call this function to set the time period (in seconds) + */ + void setDelta( double delta ); + /** + * Called on every time step for the element to update itself + */ + virtual void time_step() = 0; + +protected: + virtual bool updateStatus(); + + double m_delta; // Delta time interval +}; + +#endif diff --git a/src/electronics/simulation/resistance.cpp b/src/electronics/simulation/resistance.cpp new file mode 100644 index 0000000..9c2d25d --- /dev/null +++ b/src/electronics/simulation/resistance.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "elementset.h" +#include "matrix.h" +#include "resistance.h" + +// #include + +Resistance::Resistance( const double resistance ) + : Element::Element() +{ + m_g = resistance < 1e-9 ? 1e9 : 1./resistance; + m_numCNodes = 2; +// kdDebug() << k_funcinfo << endl; +} + +Resistance::~Resistance() +{ +// kdDebug() << k_funcinfo << endl; +} + +void Resistance::setConductance( const double g ) +{ + if ( g == m_g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Remove old resistance + m_g = -m_g; + add_initial_dc(); + + m_g = g; + add_initial_dc(); +} + + +void Resistance::setResistance( const double r ) +{ + setConductance( r < 1e-9 ? 1e9 : 1./r ); +} + + +void Resistance::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } + if ( !p_cnode[1]->isGround ) { + p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_stable, false ); + } + + if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround ) + { + p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_stable, false ); + p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } +} + + +void Resistance::add_initial_dc() +{ + if (!b_status) return; + + A_g( 0, 0 ) += m_g; + A_g( 1, 1 ) += m_g; + A_g( 0, 1 ) -= m_g; + A_g( 1, 0 ) -= m_g; +} + + +void Resistance::updateCurrents() +{ + if (!b_status) return; + const double v=p_cnode[0]->v-p_cnode[1]->v; + m_cnodeI[1] = v*m_g; + m_cnodeI[0] = -m_cnodeI[1]; +} + + + + diff --git a/src/electronics/simulation/resistance.h b/src/electronics/simulation/resistance.h new file mode 100644 index 0000000..7e5a62e --- /dev/null +++ b/src/electronics/simulation/resistance.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef RESISTANCE_H +#define RESISTANCE_H + +#include "element.h" + +/** +@short Resistance +@author David saxton +*/ +class Resistance : public Element +{ +public: + Resistance( const double resistance ); + virtual ~Resistance(); + + virtual Type type() const { return Element_Resistance; } + + void setConductance( const double g ); + void setResistance( const double r ); + + double resistance() { return 1/m_g; } + double conductance() { return m_g; } + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/vccs.cpp b/src/electronics/simulation/vccs.cpp new file mode 100644 index 0000000..7ff1bc1 --- /dev/null +++ b/src/electronics/simulation/vccs.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "elementset.h" +#include "matrix.h" +#include "vccs.h" + +VCCS::VCCS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 1; + m_numCNodes = 4; +} + + +VCCS::~VCCS() +{ +} + + +void VCCS::setGain( const double g ) +{ + if ( g == m_g ) return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + // Remove old values + m_g = -m_g; + add_initial_dc(); + + // Add new values + m_g = g; + add_initial_dc(); +} + + +void VCCS::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_stable, false ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[3]->n(), Map::et_constant, true ); + } +} + + +void VCCS::add_initial_dc() +{ + if (!b_status) + return; + + A_g( 2, 0 ) += m_g; + A_g( 3, 0 ) -= m_g; + A_g( 2, 1 ) -= m_g; + A_g( 3, 1 ) += m_g; +} + + +void VCCS::updateCurrents() +{ + if (!b_status) + return; + + m_cnodeI[0] = m_cnodeI[1] = 0.; + m_cnodeI[3] = (p_cnode[0]->v-p_cnode[1]->v)*m_g; + m_cnodeI[2] = -m_cnodeI[3]; +} + + diff --git a/src/electronics/simulation/vccs.h b/src/electronics/simulation/vccs.h new file mode 100644 index 0000000..26f1101 --- /dev/null +++ b/src/electronics/simulation/vccs.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef VCCS_H +#define VCCS_H + +#include "element.h" + +/** +CNodes n0 and n1 are used for the voltage control. +CNodes n2 and n3 are used for the current output. +@short Voltage Controlled Current Source +@author David Saxton +*/ +class VCCS : public Element +{ +public: + VCCS( const double gain ); + virtual ~VCCS(); + + virtual Type type() const { return Element_VCCS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/vcvs.cpp b/src/electronics/simulation/vcvs.cpp new file mode 100644 index 0000000..68604df --- /dev/null +++ b/src/electronics/simulation/vcvs.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "elementset.h" +#include "matrix.h" +#include "vcvs.h" + +VCVS::VCVS( const double gain ) + : Element::Element() +{ + m_g = gain; + m_numCBranches = 1; + m_numCNodes = 4; +} + + +VCVS::~VCVS() +{ +} + + +void VCVS::setGain( const double g ) +{ + if ( g == m_g ) + return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_g = -m_g; + add_initial_dc(); + + m_g = g; + add_initial_dc(); +} + + +void VCVS::add_map() +{ + if (!b_status) + return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_stable, false ); + } + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_stable, false ); + } + if ( !p_cnode[2]->isGround ) + { + p_A->setUse_b( p_cnode[2]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[2]->n(), Map::et_constant, true ); + } + if ( !p_cnode[3]->isGround ) + { + p_A->setUse_b( p_cnode[3]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[3]->n(), Map::et_constant, true ); + } +} + + +void VCVS::add_initial_dc() +{ + if (!b_status) + return; + + A_c( 0, 0 ) -= m_g; + A_c( 0, 1 ) += m_g; + A_b( 2, 0 ) = 1; + A_c( 0, 2 ) = 1; + A_b( 3, 0 ) = -1; + A_c( 0, 3 ) = -1; +} + + +void VCVS::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = m_cnodeI[1] = 0.; + m_cnodeI[3] = p_cbranch[0]->i; + m_cnodeI[2] = -m_cnodeI[3]; +} + + diff --git a/src/electronics/simulation/vcvs.h b/src/electronics/simulation/vcvs.h new file mode 100644 index 0000000..862dea9 --- /dev/null +++ b/src/electronics/simulation/vcvs.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef VCVS_H +#define VCVS_H + +#include "element.h" + +/** +Voltage source between nodes c2 and c3 +Controlling voltage between nodes c0 and c1 +@short Voltage Controlled Voltage Source +@author David Saxton +*/ +class VCVS : public Element +{ +public: + VCVS( const double gain ); + virtual ~VCVS(); + + virtual Type type() const { return Element_VCVS; } + void setGain( const double g ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_g; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/vec.cpp b/src/electronics/simulation/vec.cpp new file mode 100644 index 0000000..d45f505 --- /dev/null +++ b/src/electronics/simulation/vec.cpp @@ -0,0 +1,166 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "vec.h" + +#include +#include +#include +using namespace std; + +Vector::Vector( const int size ) +{ + m_size = size; + m_vec = new double[m_size]; + reset(); + b_changed = true; +} + + +Vector::~Vector() +{ + // Hmm...this looks like it's the correct format, although valgrind complains + // about improper memory use. Interesting. "delete m_vec" definitely leaks + // memory, so this seems like the lesser of two evils. I miss C memory allocation + // somtimes, with a nice simple free :p + delete [] m_vec; +} + + +void Vector::reset() +{ + for ( int i=0; isize() == size() ); + + for ( int i = 0; i < m_size; ++i ) + { + double limitAbs = std::abs( limitVector->m_vec[i] ); + if ( limitAbs < 1e-6 ) + limitAbs = 1e-6; + + double thisAbs = std::abs( m_vec[i] ); + if ( thisAbs < 1e-6 ) + thisAbs = 1e-6; + + if ( (thisAbs / limitAbs) > scaleMax ) + m_vec[i] /= (thisAbs / limitAbs); + + else if ( (limitAbs / thisAbs) > scaleMax ) + m_vec[i] /= (limitAbs / thisAbs); + } + b_changed = true; +} + + +void Vector::operator += ( Vector *rhs ) +{ + if (!rhs) return; + for ( int i=0; isetCacheInvalidated(); + + m_voltage = -v; + add_initial_dc(); +} + + +void VoltagePoint::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } +} + + +void VoltagePoint::add_initial_dc() +{ + if (!b_status) return; + + A_b( 0, 0 ) = -1; + A_c( 0, 0 ) = -1; + + b_v( 0 ) = m_voltage; +} + + +void VoltagePoint::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = p_cbranch[0]->i; +} + + + + + diff --git a/src/electronics/simulation/voltagepoint.h b/src/electronics/simulation/voltagepoint.h new file mode 100644 index 0000000..924b0af --- /dev/null +++ b/src/electronics/simulation/voltagepoint.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef VOLTAGEPOINT_H +#define VOLTAGEPOINT_H + +#include "element.h" + +/** +@short VoltagePoint +@author David saxton +*/ +class VoltagePoint : public Element +{ +public: + VoltagePoint( const double voltage ); + virtual ~VoltagePoint(); + + virtual Type type() const { return Element_VoltagePoint; } + void setVoltage( const double voltage ); + double voltage() { return m_voltage; } + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_voltage; // Conductance +}; + +#endif diff --git a/src/electronics/simulation/voltagesignal.cpp b/src/electronics/simulation/voltagesignal.cpp new file mode 100644 index 0000000..d7a5839 --- /dev/null +++ b/src/electronics/simulation/voltagesignal.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "matrix.h" +#include "voltagesignal.h" +#include "elementset.h" + +VoltageSignal::VoltageSignal( const double delta, const double voltage ) + : Reactive::Reactive(delta) +{ + m_voltage = voltage; + m_numCNodes = 2; + m_numCBranches = 1; +} + + +VoltageSignal::~VoltageSignal() +{ +} + + +void VoltageSignal::setVoltage( const double v ) +{ + m_voltage = v; +} + + +void VoltageSignal::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } +} + + +void VoltageSignal::add_initial_dc() +{ + if (!b_status) + return; + + A_b( 0, 0 ) = -1; + A_c( 0, 0 ) = -1; + A_b( 1, 0 ) = 1; + A_c( 0, 1 ) = 1; +} + + +void VoltageSignal::time_step() +{ + if (!b_status) return; + b_v( 0 ) = m_voltage*advance(); +} + + +void VoltageSignal::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[1] = p_cbranch[0]->i; + m_cnodeI[0] = -m_cnodeI[1]; +} + + diff --git a/src/electronics/simulation/voltagesignal.h b/src/electronics/simulation/voltagesignal.h new file mode 100644 index 0000000..5e35e72 --- /dev/null +++ b/src/electronics/simulation/voltagesignal.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef VOLTAGESIGNAL_H +#define VOLTAGESIGNAL_H + +#include "reactive.h" +#include "elementsignal.h" + +/** +@short VoltageSignal +@author David saxton +*/ +class VoltageSignal : public Reactive, public ElementSignal +{ +public: + VoltageSignal( const double delta, const double voltage ); + virtual ~VoltageSignal(); + + virtual Element::Type type() const { return Element_VoltageSignal; } + void setVoltage( const double voltage ); + double voltage() { return m_voltage; } + virtual void time_step(); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_voltage; // Voltage +}; + +#endif diff --git a/src/electronics/simulation/voltagesource.cpp b/src/electronics/simulation/voltagesource.cpp new file mode 100644 index 0000000..b4fca64 --- /dev/null +++ b/src/electronics/simulation/voltagesource.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "matrix.h" +#include "voltagesource.h" +#include "elementset.h" + +VoltageSource::VoltageSource( const double voltage ) + : Element::Element() +{ + m_v = voltage; + m_numCBranches = 1; + m_numCNodes = 2; +} + +VoltageSource::~VoltageSource() +{ +} + +void VoltageSource::setVoltage( const double v ) +{ + if ( m_v == v ) return; + + if (p_eSet) + p_eSet->setCacheInvalidated(); + + m_v = v; + add_initial_dc(); +} + + +void VoltageSource::add_map() +{ + if (!b_status) return; + + if ( !p_cnode[0]->isGround ) + { + p_A->setUse_b( p_cnode[0]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[0]->n(), Map::et_constant, true ); + } + + if ( !p_cnode[1]->isGround ) + { + p_A->setUse_b( p_cnode[1]->n(), p_cbranch[0]->n(), Map::et_constant, true ); + p_A->setUse_c( p_cbranch[0]->n(), p_cnode[1]->n(), Map::et_constant, true ); + } +} + + +void VoltageSource::add_initial_dc() +{ + if (!b_status) + return; + + A_b( 0, 0 ) = -1; + A_c( 0, 0 ) = -1; + A_b( 1, 0 ) = 1; + A_c( 0, 1 ) = 1; + + b_v( 0 ) = m_v; +} + +void VoltageSource::updateCurrents() +{ + if (!b_status) return; + m_cnodeI[0] = p_cbranch[0]->i; + m_cnodeI[1] = -m_cnodeI[0]; +} + + diff --git a/src/electronics/simulation/voltagesource.h b/src/electronics/simulation/voltagesource.h new file mode 100644 index 0000000..9b27b0d --- /dev/null +++ b/src/electronics/simulation/voltagesource.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef VOLTAGESOURCE_H +#define VOLTAGESOURCE_H + +#include "element.h" + +/** +CNode n0 is the negative terminal, CNode n1 is the positive terminal +@short Voltage Source +*/ +class VoltageSource : public Element +{ +public: + VoltageSource( const double voltage ); + virtual ~VoltageSource(); + + virtual Type type() const { return Element_VoltageSource; } + void setVoltage( const double v ); + virtual void add_map(); + +protected: + virtual void updateCurrents(); + virtual void add_initial_dc(); + +private: + double m_v; // Voltage +}; + +#endif diff --git a/src/electronics/subcircuits.cpp b/src/electronics/subcircuits.cpp new file mode 100644 index 0000000..65ae8e3 --- /dev/null +++ b/src/electronics/subcircuits.cpp @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2004-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 "ecsubcircuit.h" +#include "itemdocumentdata.h" +#include "itemlibrary.h" +#include "itemselector.h" +#include "subcircuits.h" + +#include +#include +#include +#include +#include +#include +#include + +Subcircuits::Subcircuits() + : QObject() +{ + connect( ComponentSelector::self(), SIGNAL(itemRemoved(const QString& )), this, SLOT(slotItemRemoved(const QString& )) ); +} + + +Subcircuits::~Subcircuits() +{ +} + + +void Subcircuits::initECSubcircuit( int subcircuitId, ECSubcircuit *ecSubcircuit ) +{ + const QString fileName = genFileName(subcircuitId); + if ( !QFile::exists(fileName) ) + { + kdDebug() << "Subcircuits::createSubcircuit: Subcircuit \""<(itemLibrary()->createItem( "ec/subcircuit", circuitDocument, newItem, newId, false )); + ecSubcircuit->property("id")->setValue(id); + return ecSubcircuit; +} + + +void Subcircuits::loadSubcircuits() +{ + KConfig *config = kapp->config(); + config->setGroup("Subcircuits"); + + QValueList idList = config->readIntListEntry("Ids"); + const QValueList::iterator idListEnd = idList.end(); + for ( QValueList::iterator it = idList.begin(); it != idListEnd; ++it ) + { + QFile file( genFileName(*it) ); + if ( file.open(IO_ReadOnly) == false ) + { + // File has mysteriously disappeared.... + *it = -1; + } + else + { + config->setGroup("Subcircuit_"+QString::number(*it)); + updateComponentSelector( *it, config->readEntry("Name") ); + } + file.close(); + } + idList.remove(-1); + + // Update the config file if any ids have been removed + config->setGroup("Subcircuits"); + config->writeEntry( "Ids", idList ); +} + + +QString Subcircuits::genFileName( const int nextId ) +{ + return locateLocal( "appdata", "subcircuit_"+QString::number(nextId)+".circuit" ); +} + + +void Subcircuits::updateComponentSelector( int id, const QString &name ) +{ + if ( name.isEmpty() ) + return; + + ComponentSelector::self()->addItem( name, "sc/"+QString::number(id), "Subcircuits", KGlobal::iconLoader()->loadIcon( "ktechlab_circuit", KIcon::Small ), true ); +} + + +void Subcircuits::addSubcircuit( const QString &name, const QString &subcircuitXml ) +{ + KConfig *config = kapp->config(); + config->setGroup("Subcircuits"); + + int nextId = config->readNumEntry( "NextId", 0 ); + + while ( QFile::exists( genFileName(nextId) ) ) { + nextId++; + } + + const int id = nextId; + + const QString fileName = genFileName(id); + QFile file(fileName); + + if ( file.open(IO_WriteOnly) == false ) + { + kdError() << "Subcircuits::addSubcircuit: couldn't open subcircuit save file: "< idList = config->readIntListEntry("Ids"); + idList += id; + config->writeEntry( "Ids", idList ); + config->writeEntry( "NextId", ++nextId ); + + config->setGroup("Subcircuit_"+QString::number(id)); + config->writeEntry( "Name", name ); + + // It's important that we write the configuration *now*, lest the subcircuits be lost + config->sync(); + + updateComponentSelector( id, name ); +} + + +void Subcircuits::slotItemRemoved( const QString &id ) +{ + if ( !id.startsWith("sc/") ) { + return; + } + + QString temp = id; + temp.remove("sc/"); + const int id_num = temp.toInt(); + const QString fileName = genFileName(id_num); + QFile file(fileName); + file.remove(); + + KConfig *config = kapp->config(); + config->setGroup("Subcircuits"); + QValueList idList = config->readIntListEntry("Ids"); + idList.remove(id_num); + config->writeEntry( "Ids", idList ); +} + + +#include "subcircuits.moc" + + diff --git a/src/electronics/subcircuits.h b/src/electronics/subcircuits.h new file mode 100644 index 0000000..3f08dd9 --- /dev/null +++ b/src/electronics/subcircuits.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2004 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. * + ***************************************************************************/ + +#ifndef SUBCIRCUITS_H +#define SUBCIRCUITS_H + +#include + +class CircuitDocument; +class ECSubcircuit; +class Subcircuits; +inline Subcircuits *subcircuits(); + +/** +Interface for dealing with loading / saving / etc of subcircuits +@author David Saxton +*/ +class Subcircuits : public QObject +{ +Q_OBJECT +public: + ~Subcircuits(); + /** + * Handles subcircuit creation when the user selects the subcircuit to be + * created. + * @param id Id of subcircuit; e.g. "sc/10" + */ + static ECSubcircuit* createSubcircuit( int id, CircuitDocument *circuitDocument, bool newItem, const char *newId ); + /** + * Loads a subcircuit into a subcircuit component + */ + static void initECSubcircuit( int subcircuitId, ECSubcircuit *ecSubcircuit ); + /** + * Reads in the config entries and adds the subcircuits found to the + * component selector + */ + static void loadSubcircuits(); + /** + * Saves the given subcircuit to the appdata dir, updates the appropriate + * config entries, and adds the subcircuit to the component selector. + */ + static void addSubcircuit( const QString &name, const QString &subcircuitXml ); + /** + * returns a path to the appdata dir, e.g. genFileName(2) might return + * ~/.kde/share/apps/ktechlab/subcircuit_2.circuit + */ + static QString genFileName( const int nextId ); + /** + * Adds the given entry to the component selector + */ + static void updateComponentSelector( int id, const QString &name ); + +protected slots: + void slotItemRemoved( const QString &id ); + +private: + Subcircuits(); + + friend Subcircuits* subcircuits(); +}; + + +inline Subcircuits* subcircuits() +{ + static Subcircuits *_subcircuits = new Subcircuits(); + return _subcircuits; +} + +#endif 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 +#include + +#include +#include // for rand +#include + +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="< +#include + +class CircuitDocument; +class Component; +class Pin; +class Resistance; +class QTimer; + +/** +@author David Saxton +*/ +class Switch : public QObject +{ + Q_OBJECT + + public: + enum State + { + Open, + Closed, + }; + + Switch( Component * parent, Pin * p1, Pin * p2, State state ); + ~Switch(); + /** + * If bouncing has been set to true, then the state will not switch + * immediately to that given. + */ + void setState( State state ); + State state() const { return m_state; } + /** + * Tell the switch whether to bounce or not, for the given duration, + * when the state is changed. + */ + void setBounce( bool bounce, int msec = 5 ); + /** + * Tell the switch to continue bouncing (updates the resistance value). + * Called from the simulator. + */ + void bounce(); + /** + * Attempts to calculate the current that is flowing through the switch. + * (If all the connectors at one of the ends know their currents, then + * this switch will give the current to the pins at either end). + * @return whether it was successful. + * @see CircuitDocument::calculateConnectorCurrents + */ + bool calculateCurrent(); + + protected slots: + /** + * Called from a QTimer timeout - our bouncing period has come to an + * end. This will then fully disconnect or connect the pins depending + * on the current state. + */ + void stopBouncing(); + + protected: + void startBouncing(); + + bool m_bBounce; + int m_bouncePeriod_ms; + unsigned long long m_bounceStart; // Simulator time that bouncing started + Resistance * m_pBounceResistance; + State m_state; + Component * m_pComponent; + QGuardedPtr m_pP1; + QGuardedPtr m_pP2; + QTimer * m_pStopBouncingTimer; +}; + +#endif diff --git a/src/electronics/wire.cpp b/src/electronics/wire.cpp new file mode 100644 index 0000000..619295d --- /dev/null +++ b/src/electronics/wire.cpp @@ -0,0 +1,146 @@ +/*************************************************************************** + * 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 "pin.h" +#include "wire.h" +#include + +Wire::Wire( Pin * startPin, Pin * endPin ) +{ + assert(startPin); + assert(endPin); + + m_pStartPin = startPin; + m_pEndPin = endPin; + m_current = 0.; + m_bCurrentIsKnown = false; + + m_pStartPin->addOutputWire(this); + m_pEndPin->addInputWire(this); +} + + +Wire::~Wire() +{ +} + + +bool Wire::calculateCurrent() +{ + if ( m_pStartPin->currentIsKnown() && m_pStartPin->numWires() < 2 ) + { + m_current = m_pStartPin->current(); + m_bCurrentIsKnown = true; + return true; + } + + if ( m_pEndPin->currentIsKnown() && m_pEndPin->numWires() < 2 ) + { + m_current = -m_pEndPin->current(); + m_bCurrentIsKnown = true; + return true; + } + + if ( m_pStartPin->currentIsKnown() ) + { + double i = m_pStartPin->current(); + bool ok = true; + const WireList outlist = m_pStartPin->outputWireList(); + WireList::const_iterator end = outlist.end(); + for ( WireList::const_iterator it = outlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i -= (*it)->current(); + + else + ok = false; + } + } + const WireList inlist = m_pStartPin->inputWireList(); + end = inlist.end(); + for ( WireList::const_iterator it = inlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i += (*it)->current(); + + else + ok = false; + } + } + + if (ok) + { + m_current = i; + m_bCurrentIsKnown = true; + return true; + } + } + + if ( m_pEndPin->currentIsKnown() ) + { + double i = -m_pEndPin->current(); + bool ok = true; + const WireList outlist = m_pEndPin->outputWireList(); + WireList::const_iterator end = outlist.end(); + for ( WireList::const_iterator it = outlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i += (*it)->current(); + + else + ok = false; + } + } + const WireList inlist = m_pEndPin->inputWireList(); + end = inlist.end(); + for ( WireList::const_iterator it = inlist.begin(); it != end && ok; ++it ) + { + if ( *it && (Wire*)*it != this ) + { + if ( (*it)->currentIsKnown() ) + i -= (*it)->current(); + + else + ok = false; + } + } + + if (ok) + { + m_current = i; + m_bCurrentIsKnown = true; + return true; + } + } + + m_bCurrentIsKnown = false; + return false; +} + + +double Wire::voltage() const +{ + return ( m_pStartPin->voltage() + m_pEndPin->voltage() )/2; +} + + +void Wire::setCurrentKnown( bool known ) +{ + m_bCurrentIsKnown = known; + if (!known) + m_current = 0.; +} + diff --git a/src/electronics/wire.h b/src/electronics/wire.h new file mode 100644 index 0000000..368004c --- /dev/null +++ b/src/electronics/wire.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef WIRE_H +#define WIRE_H + +#include +#include + +class Pin; + +/** +@author David Saxton +*/ +class Wire : public QObject +{ + public: + Wire( Pin * startPin, Pin * endPin ); + ~Wire(); + + /** + * Attempts to calculate the current that is flowing through + * the connector. Returns true if successfuly, otherwise returns false + */ + bool calculateCurrent(); + /** + * Returns true if the current flowing through the connector is known + */ + bool currentIsKnown() const { return m_bCurrentIsKnown; } + /** + * Set whether the actual current flowing into this node is known (in some + * cases - such as this node being ground - it is not known, and so the + * value returned by current() cannot be relied on. + */ + void setCurrentKnown( bool known ); + /** + * Returns the current flowing through the connector. + * This only applies for electronic connectors + */ + double current() const { return m_current; } + /** + * Returns the voltage at the connector. This is an average of the + * voltages at either end. + */ + double voltage() const; + + Pin * startPin() const { return m_pStartPin; } + Pin * endPin() const { return m_pEndPin; } + + protected: + double m_current; + bool m_bCurrentIsKnown; + QGuardedPtr m_pStartPin; + QGuardedPtr m_pEndPin; +}; + +#endif -- cgit v1.2.3