reworked seven segment flicker suppression; see #829

This commit is contained in:
hneemann 2021-09-15 14:10:35 +02:00
parent 4bce1db132
commit d2b1b910f2
5 changed files with 59 additions and 43 deletions

View File

@ -618,6 +618,14 @@ public final class Keys {
public static final Key<Boolean> LED_PERSISTENCE public static final Key<Boolean> LED_PERSISTENCE
= new Key<>("ledPersistence", false).allowGroupEdit().setDependsOn(COMMON_CONNECTION); = new Key<>("ledPersistence", false).allowGroupEdit().setDependsOn(COMMON_CONNECTION);
/**
* Used to enable the storage of the last state in the Seven Seg display.
*/
public static final Key<Integer> LED_PERSIST_TIME
= new Key.KeyInteger("persistTime", 0)
.setMin(0)
.allowGroupEdit();
/** /**
* Fitter for the atf15xx * Fitter for the atf15xx
*/ */

View File

@ -158,7 +158,7 @@ public class Out implements Element {
addAttribute(Keys.COLOR); addAttribute(Keys.COLOR);
addAttribute(Keys.COMMON_CONNECTION); addAttribute(Keys.COMMON_CONNECTION);
addAttribute(Keys.COMMON_CONNECTION_TYPE); addAttribute(Keys.COMMON_CONNECTION_TYPE);
addAttribute(Keys.LED_PERSISTENCE); addAttribute(Keys.LED_PERSIST_TIME);
} }
@Override @Override

View File

@ -30,12 +30,12 @@ import static de.neemann.digital.draw.shapes.GenericShape.SIZE2;
public class SevenSegShape extends SevenShape { public class SevenSegShape extends SevenShape {
private final PinDescriptions inputPins; private final PinDescriptions inputPins;
private final boolean commonConnection; private final boolean commonConnection;
private final boolean persistence; private final int persistenceTime;
private final boolean anode; private final boolean anode;
private LEDState[] ledStates; private LEDState[] ledStates;
private final boolean[] displayStates; private final boolean[] displayStates;
private Pins pins; private Pins pins;
private SegmentUpdater segmentUpdater; private PersistenceHandler persistenceHandler;
/** /**
* Creates a new instance * Creates a new instance
@ -49,7 +49,7 @@ public class SevenSegShape extends SevenShape {
this.inputPins = inputs; this.inputPins = inputs;
commonConnection = attr.get(Keys.COMMON_CONNECTION); commonConnection = attr.get(Keys.COMMON_CONNECTION);
anode = attr.get(Keys.COMMON_CONNECTION_TYPE).equals(CommonConnectionType.anode); anode = attr.get(Keys.COMMON_CONNECTION_TYPE).equals(CommonConnectionType.anode);
persistence = attr.get(Keys.LED_PERSISTENCE); persistenceTime = attr.get(Keys.LED_PERSIST_TIME);
displayStates = new boolean[8]; displayStates = new boolean[8];
} }
@ -74,23 +74,25 @@ public class SevenSegShape extends SevenShape {
@Override @Override
public Interactor applyStateMonitor(IOState ioState) { public Interactor applyStateMonitor(IOState ioState) {
ledStates = new LEDState[8]; ledStates = new LEDState[8];
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++) {
ledStates[i] = createLEDState(i, ioState.getInputs()); LEDState ledState = createLEDState(i, ioState.getInputs());
if (persistenceTime == 0)
ledStates[i] = ledState;
else
ledStates[i] = persistenceHandler.persist(ledState, persistenceTime);
}
return null; return null;
} }
@Override @Override
public void registerModel(ModelCreator modelCreator, Model model, ModelEntry element) { public void registerModel(ModelCreator modelCreator, Model model, ModelEntry element) {
if (commonConnection && persistence) if (persistenceTime > 0)
segmentUpdater = model.getOrCreateObserver(SegmentUpdater.class, SegmentUpdater::new); persistenceHandler = model.getOrCreateObserver(PersistenceHandler.class, PersistenceHandler::new);
} }
private LEDState createLEDState(int i, ObservableValues inputs) { private LEDState createLEDState(int i, ObservableValues inputs) {
if (commonConnection) { if (commonConnection) {
if (persistence) { return new CommonConnection(inputs.get(i), inputs.get(8), anode);
return new CommonConnectionPersist(inputs.get(i), inputs.get(8), segmentUpdater);
} else
return new CommonConnection(inputs.get(i), inputs.get(8));
} else { } else {
ObservableValue in = inputs.get(i); ObservableValue in = inputs.get(i);
return () -> !in.isHighZ() && in.getBool(); return () -> !in.isHighZ() && in.getBool();
@ -125,71 +127,71 @@ public class SevenSegShape extends SevenShape {
boolean getState(); boolean getState();
} }
//CHECKSTYLE.OFF: FinalClass private static final class CommonConnection implements LEDState {
private class CommonConnection implements LEDState {
private final ObservableValue led; private final ObservableValue led;
private final ObservableValue cc; private final ObservableValue cc;
private final boolean anode;
private CommonConnection(ObservableValue led, ObservableValue cc) { private CommonConnection(ObservableValue led, ObservableValue cc, boolean anode) {
this.led = led; this.led = led;
this.cc = cc; this.cc = cc;
} this.anode = anode;
protected boolean isOn() {
return (led.getBool() != cc.getBool()) && (led.getBool() ^ anode);
}
protected boolean isHighZ() {
return led.isHighZ() || cc.isHighZ();
} }
@Override @Override
public boolean getState() { public boolean getState() {
return !isHighZ() && isOn(); boolean highZ = led.isHighZ() || cc.isHighZ();
boolean on = (led.getBool() != cc.getBool()) && (led.getBool() ^ anode);
return !highZ && on;
} }
} }
//CHECKSTYLE.ON: FinalClass
private final class CommonConnectionPersist extends CommonConnection { private static final class PersistenceOfVision implements LEDState {
private boolean led; private final LEDState parent;
private final int persistenceTime;
private int timeVisible;
private CommonConnectionPersist(ObservableValue led, ObservableValue cc, SegmentUpdater segmentUpdater) { private PersistenceOfVision(LEDState parent, int persistenceTime) {
super(led, cc); this.parent = parent;
segmentUpdater.add(this); this.persistenceTime = persistenceTime;
} }
@Override @Override
public boolean getState() { public boolean getState() {
return led; return timeVisible > 0;
} }
public void updateState() { public void check() {
if (!isHighZ()) if (parent.getState())
led = isOn(); timeVisible = persistenceTime;
if (timeVisible > 0)
timeVisible--;
} }
} }
private static final class SegmentUpdater implements ModelStateObserverTyped { private static final class PersistenceHandler implements ModelStateObserverTyped {
private final ArrayList<CommonConnectionPersist> segments; private final ArrayList<PersistenceOfVision> segments;
private SegmentUpdater() { private PersistenceHandler() {
segments = new ArrayList<>(); segments = new ArrayList<>();
} }
@Override @Override
public void handleEvent(ModelEvent event) { public void handleEvent(ModelEvent event) {
if (event.getType() == ModelEventType.STEP) if (event.getType() == ModelEventType.STEP || event.getType() == ModelEventType.CHECKBURN)
for (CommonConnectionPersist c : segments) for (PersistenceOfVision ag : segments)
c.updateState(); ag.check();
} }
@Override @Override
public ModelEventType[] getEvents() { public ModelEventType[] getEvents() {
return new ModelEventType[]{ModelEventType.STEP}; return new ModelEventType[]{ModelEventType.STEP, ModelEventType.CHECKBURN};
} }
public void add(CommonConnectionPersist commonConnectionPersist) { public PersistenceOfVision persist(LEDState state, int persistenceTime) {
segments.add(commonConnectionPersist); PersistenceOfVision ag = new PersistenceOfVision(state, persistenceTime);
segments.add(ag);
return ag;
} }
} }
} }

View File

@ -1678,6 +1678,9 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="key_probeMode_DOWN">Zähle fallende Flanken</string> <string name="key_probeMode_DOWN">Zähle fallende Flanken</string>
<string name="key_probeMode_BOTH">Zähle beide Flanken</string> <string name="key_probeMode_BOTH">Zähle beide Flanken</string>
<string name="key_persistTime">Nachleuchten</string>
<string name="key_persistTime_tt">Gibt die Dauer des Nachleuchtens an. Je größer der Wert, je länger die Nachleuchtdauer.</string>
<string name="key_telnetEscape">Telnet-Modus</string> <string name="key_telnetEscape">Telnet-Modus</string>
<string name="key_telnetEscape_tt">Wenn gesetzt, werden die Telnet Steuerkommandos ausgewertet. <string name="key_telnetEscape_tt">Wenn gesetzt, werden die Telnet Steuerkommandos ausgewertet.
Zusätzlich werden vom Server die Kommandos SGA und ECHO gesendet. Zusätzlich werden vom Server die Kommandos SGA und ECHO gesendet.

View File

@ -1661,6 +1661,9 @@
<string name="key_probeMode_DOWN">Count on Falling Edge</string> <string name="key_probeMode_DOWN">Count on Falling Edge</string>
<string name="key_probeMode_BOTH">Count both Edges</string> <string name="key_probeMode_BOTH">Count both Edges</string>
<string name="key_persistTime">Persistence Of Vision</string>
<string name="key_persistTime_tt">Specifies the duration of the afterglow. The larger the value, the longer the afterglow duration.</string>
<string name="key_telnetEscape">Telnet mode</string> <string name="key_telnetEscape">Telnet mode</string>
<string name="key_telnetEscape_tt">If set, the Telnet control commands are evaluated. <string name="key_telnetEscape_tt">If set, the Telnet control commands are evaluated.
In addition, the server sends the SGA and ECHO commands. If this option is disabled, In addition, the server sends the SGA and ECHO commands. If this option is disabled,