diff --git a/src/main/java/de/neemann/digital/core/switching/Relay.java b/src/main/java/de/neemann/digital/core/switching/Relay.java index dddb629c5..7ef2b91ee 100644 --- a/src/main/java/de/neemann/digital/core/switching/Relay.java +++ b/src/main/java/de/neemann/digital/core/switching/Relay.java @@ -25,11 +25,11 @@ public class Relay extends Node implements Element { .addAttribute(Keys.ROTATE) .addAttribute(Keys.BITS) .addAttribute(Keys.LABEL) + .addAttribute(Keys.POLES) .addAttribute(Keys.RELAY_NORMALLY_CLOSED); - + private final Pole[] poles; private final boolean invers; - private final Switch s; private ObservableValue input1; private ObservableValue input2; private boolean isClosed; @@ -40,30 +40,31 @@ public class Relay extends Node implements Element { * @param attr the attributes */ public Relay(ElementAttributes attr) { - this(attr, attr.get(Keys.RELAY_NORMALLY_CLOSED)); - } - - /** - * Create a new instance - * - * @param attr the attributes - * @param invers true if relay is closed on zero in. - */ - public Relay(ElementAttributes attr, boolean invers) { - this.invers = invers; - s = new Switch(attr, invers, "out1", "out2"); + this.invers = attr.get(Keys.RELAY_NORMALLY_CLOSED); + int bits = attr.getBits(); + int poleCount = attr.get(Keys.POLES); + poles = new Pole[poleCount]; + for (int i = 0; i < poleCount; i++) + poles[i] = new Pole(bits, i + 1); } @Override public ObservableValues getOutputs() { - return s.getOutputs(); + ObservableValues.Builder ov = new ObservableValues.Builder(); + for (Pole p : poles) + p.addOutputs(ov); + return ov.build(); } @Override public void setInputs(ObservableValues inputs) throws NodeException { input1 = inputs.get(0).checkBits(1, this).addObserverToValue(this); input2 = inputs.get(1).checkBits(1, this).addObserverToValue(this); - s.setInputs(new ObservableValues(inputs.get(2), inputs.get(3))); + int i = 2; + for (Pole p : poles) { + p.setInputs(inputs.get(i), inputs.get(i + 1)); + i += 2; + } } @Override @@ -76,12 +77,14 @@ public class Relay extends Node implements Element { @Override public void writeOutputs() { - s.setClosed(isClosed); + for (Pole p : poles) + p.setClosed(isClosed); } @Override public void init(Model model) { - s.init(model); + for (Pole p : poles) + p.init(model); } /** @@ -90,4 +93,32 @@ public class Relay extends Node implements Element { public boolean isClosed() { return isClosed; } + + private static final class Pole { + private final Switch s; + private final ObservableValue outputA; + private final ObservableValue outputB; + + private Pole(int bits, int num) { + outputA = new ObservableValue("A" + num, bits).setBidirectional().setToHighZ(); + outputB = new ObservableValue("B" + num, bits).setBidirectional().setToHighZ(); + s = new Switch(outputA, outputB, false); + } + + private void addOutputs(ObservableValues.Builder ov) { + ov.add(outputA, outputB); + } + + public void setInputs(ObservableValue inA, ObservableValue inB) throws NodeException { + s.setInputs(new ObservableValues(inA, inB)); + } + + public void init(Model model) { + s.init(model); + } + + public void setClosed(boolean isClosed) { + s.setClosed(isClosed); + } + } } diff --git a/src/main/java/de/neemann/digital/draw/shapes/RelayShape.java b/src/main/java/de/neemann/digital/draw/shapes/RelayShape.java index 250fdf794..2b83d4ead 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/RelayShape.java +++ b/src/main/java/de/neemann/digital/draw/shapes/RelayShape.java @@ -26,9 +26,10 @@ public class RelayShape implements Shape { private final PinDescriptions inputs; private final PinDescriptions outputs; private final String label; - private boolean invers; + private final int poles; private Relay relay; private boolean relayIsClosed; + private Pins pins; /** * Creates a new instance @@ -43,15 +44,25 @@ public class RelayShape implements Shape { invers = attributes.get(Keys.RELAY_NORMALLY_CLOSED); relayIsClosed = invers; label = attributes.getCleanLabel(); + poles = attributes.get(Keys.POLES); } @Override public Pins getPins() { - return new Pins() - .add(new Pin(new Vector(0, -SIZE * 2), inputs.get(0))) - .add(new Pin(new Vector(SIZE * 2, -SIZE * 2), inputs.get(1))) - .add(new Pin(new Vector(0, 0), outputs.get(0))) - .add(new Pin(new Vector(SIZE * 2, 0), outputs.get(1))); + if (pins == null) { + pins = new Pins() + .add(new Pin(new Vector(0, -SIZE * 2), inputs.get(0))) + .add(new Pin(new Vector(SIZE * 2, -SIZE * 2), inputs.get(1))); + final int relayStepY = 2 * SIZE; + int relayBaseY = 0; + for (int p = 0; p < poles; p++) { + pins + .add(new Pin(new Vector(0, relayBaseY), outputs.get(p * 2))) + .add(new Pin(new Vector(SIZE * 2, relayBaseY), outputs.get(p * 2 + 1))); + relayBaseY += relayStepY; + } + } + return pins; } @Override @@ -70,16 +81,28 @@ public class RelayShape implements Shape { @Override public void drawTo(Graphic graphic, Style highLight) { - int yOffs = 0; - + final int relayTipY; + final int relayTipX; if (relayIsClosed) { - graphic.drawLine(new Vector(0, 0), new Vector(SIZE * 2, 0), Style.NORMAL); + relayTipX = SIZE * 2; + relayTipY = 0; } else { - yOffs = SIZE2 / 2; - graphic.drawLine(new Vector(0, 0), new Vector(SIZE * 2 - 4, -yOffs * 2), Style.NORMAL); + relayTipX = (SIZE * 2) - 4; + relayTipY = SIZE2; } - graphic.drawLine(new Vector(SIZE, -yOffs), new Vector(SIZE, 1 - SIZE), Style.DASH); + final int relayStepY = 2 * SIZE; + int relayBaseY = 0; + for (int p = 0; p < poles; p++) { + graphic.drawLine(new Vector(0, relayBaseY), new Vector(relayTipX, relayBaseY - relayTipY), Style.NORMAL); + relayBaseY += relayStepY; + } + + final int yOffs = (SIZE / 4) + (relayTipY / 2); + graphic.drawLine(new Vector(SIZE, (poles - 1) * SIZE * 2 - yOffs), new Vector(SIZE, 1 - SIZE), Style.DASH); + + + // the coil graphic.drawPolygon(new Polygon(true) .add(SIZE2, -SIZE) .add(SIZE2, -SIZE * 3) diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index afecc8502..fc701817f 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -670,8 +670,6 @@ Das Relais verhält sich damit ähnlich wie ein XOr Gatter. Ein Steuereingang des Relais. Ein Steuereingang des Relais. - Einer der Ausgänge des gesteuerten Schalters. - Einer der Ausgänge des gesteuerten Schalters. Relais mit Wechselkontakt Ein Relais ist ein Schalter, welcher über eine Spule umgeschaltet werden kann. Wenn ein Strom durch das Relais fließt, wird der Schalter geöffnet bzw. geschlossen. diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 0c6bbf662..0c06cca57 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -668,8 +668,6 @@ The relay behaves similar to an XOr gate. On of the inputs to control the relay. On of the inputs to control the relay. - One of the switch outputs. - One of the switch outputs. Double Throw Relay A relay is a switch which can be controlled by a coil. If a current flows through the coil, the switch is closed or opened. diff --git a/src/test/java/de/neemann/digital/lang/TestElemConsistence.java b/src/test/java/de/neemann/digital/lang/TestElemConsistence.java index 7d7fffb03..9ac765ddc 100644 --- a/src/test/java/de/neemann/digital/lang/TestElemConsistence.java +++ b/src/test/java/de/neemann/digital/lang/TestElemConsistence.java @@ -11,6 +11,7 @@ import de.neemann.digital.core.element.*; import de.neemann.digital.core.extern.External; import de.neemann.digital.core.memory.LookUpTable; import de.neemann.digital.core.switching.RelayDT; +import de.neemann.digital.core.switching.Relay; import de.neemann.digital.core.wiring.*; import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.graphics.GraphicSVG; @@ -70,6 +71,7 @@ public class TestElemConsistence extends TestCase { || e instanceof BusSplitter || e instanceof External || e instanceof LookUpTable + || e instanceof Relay || e instanceof RelayDT); }