mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-09 12:56:02 -04:00
adds a triggered scope, closes #571
This commit is contained in:
parent
fa42431b05
commit
ac0d9db8be
@ -27,6 +27,7 @@ import de.neemann.digital.draw.elements.Tunnel;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.gui.Settings;
|
||||
import de.neemann.digital.gui.components.data.DummyElement;
|
||||
import de.neemann.digital.gui.components.data.ScopeTrigger;
|
||||
import de.neemann.digital.gui.components.graphics.GraphicCard;
|
||||
import de.neemann.digital.gui.components.graphics.LedMatrix;
|
||||
import de.neemann.digital.gui.components.graphics.VGA;
|
||||
@ -130,6 +131,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
|
||||
.add(DummyElement.TEXTDESCRIPTION)
|
||||
.add(Probe.DESCRIPTION)
|
||||
.add(DummyElement.DATADESCRIPTION)
|
||||
.add(ScopeTrigger.DESCRIPTION)
|
||||
.add(new LibraryNode(Lang.get("lib_displays"))
|
||||
.add(RGBLED.DESCRIPTION)
|
||||
.add(Out.POLARITYAWARELEDDESCRIPTION)
|
||||
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Helmut Neemann.
|
||||
* Use of this source code is governed by the GPL v3 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package de.neemann.digital.gui.components.data;
|
||||
|
||||
import de.neemann.digital.core.*;
|
||||
import de.neemann.digital.core.element.Element;
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
import de.neemann.digital.data.Value;
|
||||
import de.neemann.digital.data.ValueTable;
|
||||
import de.neemann.digital.draw.elements.PinException;
|
||||
import de.neemann.digital.gui.Main;
|
||||
import de.neemann.digital.gui.components.OrderMerger;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.testing.parser.TestRow;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static de.neemann.digital.core.element.PinInfo.input;
|
||||
|
||||
/**
|
||||
* The ScopeElement
|
||||
*/
|
||||
public class ScopeTrigger extends Node implements Element {
|
||||
|
||||
/**
|
||||
* The ScopeElement description
|
||||
*/
|
||||
public static final ElementTypeDescription DESCRIPTION =
|
||||
new ElementTypeDescription(ScopeTrigger.class, input("T").setClock())
|
||||
.addAttribute(Keys.LABEL)
|
||||
.addAttribute(Keys.MAX_STEP_COUNT);
|
||||
|
||||
private final int maxSize;
|
||||
private final String label;
|
||||
private ObservableValue clockValue;
|
||||
private boolean lastClock;
|
||||
private ValueTable logData;
|
||||
private ArrayList<Signal> signals;
|
||||
private Model model;
|
||||
private GraphDialog graphDialog;
|
||||
private boolean clockHasChanged;
|
||||
private ScopeModelStateObserver scopeModelStateObserver;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param attr the elements attributes
|
||||
*/
|
||||
public ScopeTrigger(ElementAttributes attr) {
|
||||
label = attr.getLabel();
|
||||
maxSize = attr.get(Keys.MAX_STEP_COUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputs(ObservableValues inputs) throws NodeException {
|
||||
clockValue = inputs.get(0).checkBits(1, this).addObserverToValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readInputs() throws NodeException {
|
||||
boolean clock = clockValue.getBool();
|
||||
if (clock != lastClock)
|
||||
clockHasChanged = true;
|
||||
lastClock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeOutputs() throws NodeException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValues getOutputs() throws PinException {
|
||||
return ObservableValues.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Model model) throws NodeException {
|
||||
signals = model.getSignalsCopy();
|
||||
this.model = model;
|
||||
signals.removeIf(signal -> !signal.isShowInGraph());
|
||||
|
||||
String[] names = new String[signals.size()];
|
||||
for (int i = 0; i < signals.size(); i++)
|
||||
names[i] = signals.get(i).getName();
|
||||
|
||||
JFrame m = model.getWindowPosManager().getMainFrame();
|
||||
if (m instanceof Main) {
|
||||
List<String> ordering = ((Main) m).getCircuitComponent().getCircuit().getMeasurementOrdering();
|
||||
new OrderMerger<String, Signal>(ordering) {
|
||||
@Override
|
||||
public boolean equals(Signal a, String b) {
|
||||
return a.getName().equals(b);
|
||||
}
|
||||
}.order(signals);
|
||||
}
|
||||
|
||||
this.logData = new ValueTable(names).setMaxSize(maxSize);
|
||||
|
||||
scopeModelStateObserver = new ScopeModelStateObserver();
|
||||
model.addObserver(scopeModelStateObserver, ModelEventType.STEP);
|
||||
}
|
||||
|
||||
private final class ScopeModelStateObserver implements ModelStateObserver {
|
||||
@Override
|
||||
public void handleEvent(ModelEvent event) {
|
||||
if (clockHasChanged && event.getType() == ModelEventType.STEP) {
|
||||
Value[] sample = new Value[logData.getColumns()];
|
||||
for (int i = 0; i < logData.getColumns(); i++)
|
||||
sample[i] = new Value(signals.get(i).getValue());
|
||||
|
||||
logData.add(new TestRow(sample));
|
||||
clockHasChanged = false;
|
||||
|
||||
if (graphDialog == null || !graphDialog.isVisible()) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
String title = label;
|
||||
if (title.isEmpty())
|
||||
title = Lang.get("elem_ScopeTrigger_short");
|
||||
graphDialog = new GraphDialog(model.getWindowPosManager().getMainFrame(), title, logData);
|
||||
graphDialog.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
model.modify(() -> model.removeObserver(scopeModelStateObserver));
|
||||
}
|
||||
});
|
||||
graphDialog.setVisible(true);
|
||||
model.getWindowPosManager().register("Scope_" + label, graphDialog);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -243,6 +243,16 @@
|
||||
Es können sowohl komplette Taktschritte als auch einzelne Gatter-Veränderungen angezeigt werden.
|
||||
Hat keine weitere Funktion für die Simulation.
|
||||
</string>
|
||||
<string name="elem_ScopeTrigger">Getriggerter Messwertgraph</string>
|
||||
<string name="elem_ScopeTrigger_short">Scope</string>
|
||||
<string name="elem_ScopeTrigger_tt">Zeigt einen Messwertgraph, wobei nur dann Messwerte gespeichert werden,
|
||||
wenn sich das Eingangssignal verändert.
|
||||
Das Speichern findet statt, wenn sich die Schaltung stabilisiert hat.
|
||||
Der Trigger startet nicht die Messung wie bei einem echten Scope, sondern jedes Triggerereignis
|
||||
speichert einen einzigen Messwert für jedes der angezeigten Signale.
|
||||
</string>
|
||||
<string name="elem_ScopeTrigger_pin_T">Ein Änderung an diesem Eingang veranlasst das Speichern von Messwerten.</string>
|
||||
|
||||
<string name="elem_RotEncoder">Drehencoder</string>
|
||||
<string name="elem_RotEncoder_tt">Drehknopf mit Drehencoder zur Erfassung einer Drehbewegung.</string>
|
||||
<string name="elem_RotEncoder_pin_A">Encodersignal A</string>
|
||||
|
@ -247,6 +247,15 @@
|
||||
You can plot complete clock cycles or single gate changes.
|
||||
Does not affect the simulation.
|
||||
</string>
|
||||
<string name="elem_ScopeTrigger">Triggered Data Graph</string>
|
||||
<string name="elem_ScopeTrigger_short">Scope</string>
|
||||
<string name="elem_ScopeTrigger_tt">Shows a graph of measured values, whereby measured values are only stored if
|
||||
the input signal changes. Storing takes place when the circuit has stabilized.
|
||||
The trigger does not start the measurement like in a real scope, but each trigger event stores a single
|
||||
measurement value for each of the shown signals.
|
||||
</string>
|
||||
<string name="elem_ScopeTrigger_pin_T">A change at this input causes measured values to be stored.</string>
|
||||
|
||||
<string name="elem_RotEncoder">Rotary Encoder</string>
|
||||
<string name="elem_RotEncoder_tt">Rotary knob with rotary encoder. Used to detect rotational movements.</string>
|
||||
<string name="elem_RotEncoder_pin_A">encoder signal A</string>
|
||||
|
@ -682,6 +682,11 @@
|
||||
</elementAttributes>
|
||||
<pos x="800" y="480"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>ScopeTrigger</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="820" y="940"/>
|
||||
</visualElement>
|
||||
</visualElements>
|
||||
<wires>
|
||||
<wire>
|
||||
@ -940,6 +945,10 @@
|
||||
<p1 x="580" y="940"/>
|
||||
<p2 x="800" y="940"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="800" y="940"/>
|
||||
<p2 x="820" y="940"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="280" y="940"/>
|
||||
<p2 x="300" y="940"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user