From 4bce1db132afe0787668390d3d881feaa7e77476 Mon Sep 17 00:00:00 2001 From: hneemann Date: Wed, 15 Sep 2021 11:04:26 +0200 Subject: [PATCH] fixes an issue with seven segment flicker suppression; closes #829 --- .../java/de/neemann/digital/core/Model.java | 32 ++++++++++ .../digital/core/wiring/bus/DataBus.java | 6 +- .../digital/draw/shapes/SevenSegShape.java | 63 ++++++++++++++----- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/neemann/digital/core/Model.java b/src/main/java/de/neemann/digital/core/Model.java index e401d4d97..c9f648731 100644 --- a/src/main/java/de/neemann/digital/core/Model.java +++ b/src/main/java/de/neemann/digital/core/Model.java @@ -583,6 +583,26 @@ public class Model implements Iterable, SyncAccess { return null; } + /** + * Gets an observer of the given class. + * If no observer is available the factory is used to create and register one. + * + * @param observerClass the observers class + * @param factory the factory to create an instance if necessary + * @param the type of the observer + * @return the already present or newly created observer; never null + */ + public synchronized T getOrCreateObserver(Class observerClass, ObserverFactory factory) { + T o = getObserver(observerClass); + if (o == null) { + o = factory.create(); + if (o == null) + throw new NullPointerException("no observer created!"); + addObserver(o); + } + return o; + } + private void fireEvent(ModelEvent event) { switch (event.getType()) { case MICROSTEP: @@ -1083,4 +1103,16 @@ public class Model implements Iterable, SyncAccess { private interface StepCondition { boolean doNextMicroStep() throws NodeException; } + + /** + * Factory used to create a {@link ModelStateObserverTyped} + * + * @param the type of the observer + */ + public interface ObserverFactory { + /** + * @return the created observer + */ + T create(); + } } diff --git a/src/main/java/de/neemann/digital/core/wiring/bus/DataBus.java b/src/main/java/de/neemann/digital/core/wiring/bus/DataBus.java index 79f9dcce5..19dde8df3 100644 --- a/src/main/java/de/neemann/digital/core/wiring/bus/DataBus.java +++ b/src/main/java/de/neemann/digital/core/wiring/bus/DataBus.java @@ -80,11 +80,7 @@ public class DataBus { } } - BusModelStateObserver obs = model.getObserver(BusModelStateObserver.class); - if (obs == null) { - obs = new BusModelStateObserver(); - model.addObserver(obs); - } + BusModelStateObserver obs = model.getOrCreateObserver(BusModelStateObserver.class, BusModelStateObserver::new); commonBusValue = new CommonBusValue(bits, obs, resistor, outputs, net == null ? null : net.getOrigin()); for (ObservableValue p : outputs) diff --git a/src/main/java/de/neemann/digital/draw/shapes/SevenSegShape.java b/src/main/java/de/neemann/digital/draw/shapes/SevenSegShape.java index efa54d2ac..80c891d13 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/SevenSegShape.java +++ b/src/main/java/de/neemann/digital/draw/shapes/SevenSegShape.java @@ -5,9 +5,7 @@ */ package de.neemann.digital.draw.shapes; -import de.neemann.digital.core.ObservableValue; -import de.neemann.digital.core.ObservableValues; -import de.neemann.digital.core.Observer; +import de.neemann.digital.core.*; import de.neemann.digital.core.element.ElementAttributes; import de.neemann.digital.core.element.Keys; import de.neemann.digital.core.element.PinDescriptions; @@ -18,6 +16,10 @@ import de.neemann.digital.draw.elements.Pins; import de.neemann.digital.draw.graphics.Graphic; import de.neemann.digital.draw.graphics.Style; import de.neemann.digital.draw.graphics.Vector; +import de.neemann.digital.draw.model.ModelCreator; +import de.neemann.digital.draw.model.ModelEntry; + +import java.util.ArrayList; import static de.neemann.digital.draw.shapes.GenericShape.SIZE; import static de.neemann.digital.draw.shapes.GenericShape.SIZE2; @@ -33,6 +35,7 @@ public class SevenSegShape extends SevenShape { private LEDState[] ledStates; private final boolean[] displayStates; private Pins pins; + private SegmentUpdater segmentUpdater; /** * Creates a new instance @@ -76,11 +79,17 @@ public class SevenSegShape extends SevenShape { return null; } + @Override + public void registerModel(ModelCreator modelCreator, Model model, ModelEntry element) { + if (commonConnection && persistence) + segmentUpdater = model.getOrCreateObserver(SegmentUpdater.class, SegmentUpdater::new); + } + private LEDState createLEDState(int i, ObservableValues inputs) { if (commonConnection) { - if (persistence) - return new CommonConnectionPersist(inputs.get(i), inputs.get(8)); - else + if (persistence) { + return new CommonConnectionPersist(inputs.get(i), inputs.get(8), segmentUpdater); + } else return new CommonConnection(inputs.get(i), inputs.get(8)); } else { ObservableValue in = inputs.get(i); @@ -141,24 +150,46 @@ public class SevenSegShape extends SevenShape { } //CHECKSTYLE.ON: FinalClass - private final class CommonConnectionPersist extends CommonConnection implements Observer { + private final class CommonConnectionPersist extends CommonConnection { private boolean led; - private CommonConnectionPersist(ObservableValue led, ObservableValue cc) { + private CommonConnectionPersist(ObservableValue led, ObservableValue cc, SegmentUpdater segmentUpdater) { super(led, cc); - led.addObserver(this); - cc.addObserver(this); - } - - @Override - public void hasChanged() { - if (!isHighZ()) - led = isOn(); + segmentUpdater.add(this); } @Override public boolean getState() { return led; } + + public void updateState() { + if (!isHighZ()) + led = isOn(); + } + } + + private static final class SegmentUpdater implements ModelStateObserverTyped { + private final ArrayList segments; + + private SegmentUpdater() { + segments = new ArrayList<>(); + } + + @Override + public void handleEvent(ModelEvent event) { + if (event.getType() == ModelEventType.STEP) + for (CommonConnectionPersist c : segments) + c.updateState(); + } + + @Override + public ModelEventType[] getEvents() { + return new ModelEventType[]{ModelEventType.STEP}; + } + + public void add(CommonConnectionPersist commonConnectionPersist) { + segments.add(commonConnectionPersist); + } } }