mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 08:55:05 -04:00
Added a clock input to the keyboard component. See #138
This commit is contained in:
parent
5627357b12
commit
52c4efb6e2
@ -3,8 +3,9 @@ Release Notes
|
||||
HEAD, planned as v0.19
|
||||
- Added support for asynchronous sequential circuits such as the Muller-pipeline.
|
||||
Take a look at the new asynchronous examples for illustration.
|
||||
- Braking changes:
|
||||
- Breaking changes:
|
||||
- Added an enable input to the terminal component.
|
||||
- Added a clock input to the keyboard component.
|
||||
- Bug fixes
|
||||
- Fixed a bug in the VHDL export concerning an invalid optimization of a
|
||||
std_logic_vector access.
|
||||
|
@ -35,6 +35,8 @@ import de.neemann.digital.gui.components.modification.Modifications;
|
||||
import de.neemann.digital.gui.components.modification.ModifyAttribute;
|
||||
import de.neemann.digital.gui.components.modification.ModifyMeasurementOrdering;
|
||||
import de.neemann.digital.gui.components.table.TableDialog;
|
||||
import de.neemann.digital.gui.components.terminal.Keyboard;
|
||||
import de.neemann.digital.gui.components.terminal.KeyboardDialog;
|
||||
import de.neemann.digital.gui.components.testing.ValueTableDialog;
|
||||
import de.neemann.digital.gui.components.tree.LibraryTreeModel;
|
||||
import de.neemann.digital.gui.components.tree.SelectTree;
|
||||
@ -1221,6 +1223,8 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
// all repainting is initiated by user actions!
|
||||
modelCreator.connectToGui(null);
|
||||
|
||||
handleKeyboardComponent(updateEvent, modelSync);
|
||||
|
||||
doStep.setEnabled(false);
|
||||
runToBreakAction.setEnabled(!realTimeClockRunning && model.isFastRunModel());
|
||||
|
||||
@ -1250,6 +1254,37 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleKeyboardComponent(ModelEvent updateEvent, Sync modelSync) {
|
||||
KeyboardDialog.KeyPressedHandler handler = null;
|
||||
for (Keyboard k : model.findNode(Keyboard.class)) {
|
||||
if (handler == null)
|
||||
if (updateEvent == ModelEvent.MICROSTEP)
|
||||
handler = keyboard -> {
|
||||
keyboard.hasChanged();
|
||||
modelCreator.addNodeElementsTo(model.nodesToUpdate(), circuitComponent.getHighLighted());
|
||||
model.fireManualChangeEvent();
|
||||
doStep.setEnabled(model.needsUpdate());
|
||||
circuitComponent.repaintNeeded();
|
||||
};
|
||||
else
|
||||
handler = keyboard -> {
|
||||
try {
|
||||
modelSync.accessNEx(() -> {
|
||||
keyboard.hasChanged();
|
||||
model.fireManualChangeEvent();
|
||||
model.doStep();
|
||||
});
|
||||
circuitComponent.repaintNeeded();
|
||||
} catch (NodeException | RuntimeException e) {
|
||||
showErrorAndStopModel(Lang.get("msg_errorCalculatingStep"), e);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
windowPosManager.register("keyboard_" + k.getLabel(), new KeyboardDialog(this, k, handler));
|
||||
}
|
||||
}
|
||||
|
||||
private void showMeasurementGraph(ModelEvent updateEvent) {
|
||||
List<String> ordering = circuitComponent.getCircuit().getMeasurementOrdering();
|
||||
windowPosManager.register("dataSet", GraphDialog.createLiveDialog(this, model, updateEvent == ModelEvent.MICROSTEP, ordering, modelSync)).setVisible(true);
|
||||
|
@ -14,8 +14,6 @@ import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||
import de.neemann.digital.core.element.Keys;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static de.neemann.digital.core.element.PinInfo.input;
|
||||
|
||||
/**
|
||||
@ -27,17 +25,20 @@ public class Keyboard extends Node implements Element {
|
||||
*/
|
||||
public static final ElementTypeDescription DESCRIPTION
|
||||
= new ElementTypeDescription(Keyboard.class,
|
||||
input("sel"))
|
||||
input("C").setClock(),
|
||||
input("en"))
|
||||
.addAttribute(Keys.ROTATE)
|
||||
.addAttribute(Keys.LABEL);
|
||||
.addAttribute(Keys.LABEL)
|
||||
.addAttribute(Keys.INVERTER_CONFIG);
|
||||
|
||||
private final String label;
|
||||
private KeyboardDialog keyboardDialog;
|
||||
private ObservableValue data;
|
||||
private ObservableValue select;
|
||||
private boolean sel;
|
||||
private boolean lastSel = false;
|
||||
private int keyData;
|
||||
private final ObservableValue data;
|
||||
private final ObservableValue isKeyOut;
|
||||
private KeyboardInterface keyboardInterface;
|
||||
private ObservableValue clock;
|
||||
private ObservableValue enable;
|
||||
private boolean enableVal;
|
||||
private boolean lastClock = false;
|
||||
|
||||
/**
|
||||
* Creates a new terminal instance
|
||||
@ -48,49 +49,83 @@ public class Keyboard extends Node implements Element {
|
||||
data = new ObservableValue("D", 16)
|
||||
.setToHighZ()
|
||||
.setPinDescription(DESCRIPTION);
|
||||
isKeyOut = new ObservableValue("av", 1)
|
||||
.setPinDescription(DESCRIPTION);
|
||||
label = attributes.getCleanLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputs(ObservableValues inputs) throws NodeException {
|
||||
select = inputs.get(0).addObserverToValue(this).checkBits(1, this);
|
||||
clock = inputs.get(0).addObserverToValue(this).checkBits(1, this, 0);
|
||||
enable = inputs.get(1).addObserverToValue(this).checkBits(1, this, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValues getOutputs() {
|
||||
return data.asList();
|
||||
return new ObservableValues(data, isKeyOut);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readInputs() throws NodeException {
|
||||
sel = select.getBool();
|
||||
if (!lastSel && sel) {
|
||||
KeyboardDialog kbd = getKeyboard();
|
||||
if (kbd != null)
|
||||
keyData = kbd.getChar();
|
||||
else
|
||||
keyData = 0;
|
||||
}
|
||||
lastSel = sel;
|
||||
enableVal = enable.getBool();
|
||||
boolean nowClock = clock.getBool();
|
||||
|
||||
if (keyboardInterface != null && nowClock && !lastClock && enableVal)
|
||||
keyboardInterface.removeChar();
|
||||
|
||||
lastClock = nowClock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeOutputs() throws NodeException {
|
||||
if (sel)
|
||||
data.setValue(keyData);
|
||||
else
|
||||
data.setToHighZ();
|
||||
if (keyboardInterface != null) {
|
||||
if (enableVal)
|
||||
data.setValue(keyboardInterface.getChar());
|
||||
else
|
||||
data.setToHighZ();
|
||||
isKeyOut.setBool(keyboardInterface.isChar());
|
||||
} else {
|
||||
if (enableVal)
|
||||
data.setValue(0);
|
||||
else
|
||||
data.setToHighZ();
|
||||
isKeyOut.setBool(false);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyboardDialog getKeyboard() {
|
||||
if (keyboardDialog == null || !keyboardDialog.isVisible()) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (keyboardDialog == null || !keyboardDialog.isVisible()) {
|
||||
keyboardDialog = new KeyboardDialog(getModel().getWindowPosManager().getMainFrame());
|
||||
getModel().getWindowPosManager().register("keyboard_" + label, keyboardDialog);
|
||||
}
|
||||
});
|
||||
}
|
||||
return keyboardDialog;
|
||||
/**
|
||||
* Sets the keyboard interface
|
||||
*
|
||||
* @param keyboardInterface the keyboard interface
|
||||
*/
|
||||
public void setKeyboardDialog(KeyboardInterface keyboardInterface) {
|
||||
this.keyboardInterface = keyboardInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the keyboard label
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* The keyboard interface
|
||||
*/
|
||||
public interface KeyboardInterface {
|
||||
/**
|
||||
* @return a char or 0 if no char available
|
||||
*/
|
||||
int getChar();
|
||||
|
||||
/**
|
||||
* @return true if there is a char
|
||||
*/
|
||||
boolean isChar();
|
||||
|
||||
/**
|
||||
* removes the first character
|
||||
*/
|
||||
void removeChar();
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import java.awt.event.KeyEvent;
|
||||
/**
|
||||
* A simple keyboard implementation
|
||||
*/
|
||||
public class KeyboardDialog extends JDialog {
|
||||
public class KeyboardDialog extends JDialog implements Keyboard.KeyboardInterface {
|
||||
private final JLabel textLabel;
|
||||
private final Object textLock = new Object();
|
||||
private String text;
|
||||
@ -23,13 +23,15 @@ public class KeyboardDialog extends JDialog {
|
||||
/**
|
||||
* Create a new Instance
|
||||
*
|
||||
* @param owner the owner frame
|
||||
* @param owner the owner frame
|
||||
* @param keyboard the keyboard node which has opened this dialog
|
||||
* @param keyPressedHandler handler called every time a key is typed
|
||||
*/
|
||||
public KeyboardDialog(Frame owner) {
|
||||
super(owner, Lang.get("elem_Keyboard"), false);
|
||||
public KeyboardDialog(Frame owner, Keyboard keyboard, KeyPressedHandler keyPressedHandler) {
|
||||
super(owner, Lang.get("elem_Keyboard") + " " + keyboard.getLabel(), false);
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
||||
textLabel = new JLabel("Enter Text ");
|
||||
textLabel = new JLabel(Lang.get("msg_enterText") + " ");
|
||||
textLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
getContentPane().add(textLabel);
|
||||
text = "";
|
||||
@ -43,6 +45,7 @@ public class KeyboardDialog extends JDialog {
|
||||
text += e.getKeyChar();
|
||||
t = text;
|
||||
}
|
||||
keyPressedHandler.keyPressed(keyboard);
|
||||
textLabel.setText(t);
|
||||
}
|
||||
});
|
||||
@ -50,24 +53,47 @@ public class KeyboardDialog extends JDialog {
|
||||
pack();
|
||||
setLocationRelativeTo(owner);
|
||||
setVisible(true);
|
||||
|
||||
keyboard.setKeyboardDialog(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the oldest char
|
||||
*/
|
||||
@Override
|
||||
public int getChar() {
|
||||
synchronized (textLock) {
|
||||
if (text.length() == 0)
|
||||
return 0;
|
||||
else {
|
||||
int c = text.charAt(0);
|
||||
String t;
|
||||
else
|
||||
return text.charAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChar() {
|
||||
synchronized (textLock) {
|
||||
return text.length() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChar() {
|
||||
synchronized (textLock) {
|
||||
if (text.length() > 0) {
|
||||
text = text.substring(1);
|
||||
t = text;
|
||||
final String t = text;
|
||||
SwingUtilities.invokeLater(() -> textLabel.setText(t));
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The handler called if a key is typed.
|
||||
*/
|
||||
public interface KeyPressedHandler {
|
||||
/**
|
||||
* Called if a key is typed
|
||||
*
|
||||
* @param keyboard the keyboard used
|
||||
*/
|
||||
void keyPressed(Keyboard keyboard);
|
||||
}
|
||||
}
|
||||
|
@ -224,8 +224,13 @@
|
||||
Dieses Element puffert die Eingaben, welche dann ausgelesen werden können.
|
||||
Es wird ein eigenes Fenster für die Eingabe geöffnet.
|
||||
</string>
|
||||
<string name="elem_Keyboard_pin_sel">Wenn gesetzt, ist der Ausgang D aktiv und ein Tastendruck wird ausgegeben.</string>
|
||||
<string name="elem_Keyboard_pin_C">Takt. Eine steigende Flanke entfernt das älteste Zeichen aus dem Buffer.</string>
|
||||
<string name="elem_Keyboard_pin_en">Wenn gesetzt, ist der Ausgang D aktiv und ein Tastendruck wird ausgegeben.
|
||||
Ist gleichzeitig die freigabe für den Takt.</string>
|
||||
<string name="elem_Keyboard_pin_D">Die letzte Taste oder 0, wenn keine Taste gedrückt.</string>
|
||||
<string name="elem_Keyboard_pin_av">Dieser Ausgang zeigt an, dass Zeichen vorhanden sind.
|
||||
Er kann genutzt werden, um einen Interrupt auszulösen.</string>
|
||||
|
||||
<string name="elem_Terminal">Terminal</string>
|
||||
<string name="elem_Terminal_tt">Ein Terminal, auf dem ASCII-Zeichen ausgegeben werden können.
|
||||
Öffnet ein eigenes Fenster, um die Ausgabe anzuzeigen.</string>
|
||||
@ -1429,6 +1434,7 @@ Soll dennoch exportiert werden?</string>
|
||||
nicht der Fall ist, wird die Fehlermeldung der externen Anwendung angezeigt. Wenn es möglich ist, werden zudem
|
||||
die Eingangs- und Ausgangsdefinitionen an den aktuellen Code angepasst.</string>
|
||||
<string name="msg_applicationFileNotFound">Ausführbare Datei "{0}" nicht gefunden!</string>
|
||||
<string name="msg_enterText">Text eingeben!</string>
|
||||
|
||||
<string name="ok">Ok</string>
|
||||
<string name="rot_0">0°</string>
|
||||
|
@ -223,13 +223,19 @@
|
||||
<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>
|
||||
<string name="elem_RotEncoder_pin_B">encoder signal B</string>
|
||||
|
||||
<string name="elem_Keyboard">Keyboard</string>
|
||||
<string name="elem_Keyboard_tt">A keyboard that can be used to enter text.
|
||||
This component buffers the inputs, which can then be read out.
|
||||
This component buffers the input, which can then be read out.
|
||||
A separate window is opened for the text input.
|
||||
</string>
|
||||
<string name="elem_Keyboard_pin_sel">If high the output D is active and one keystroke is output.</string>
|
||||
<string name="elem_Keyboard_pin_D">The last pressed key, or zero if no key is typed.</string>
|
||||
<string name="elem_Keyboard_pin_C">Clock. A rising edge removes the oldest character from the buffer.</string>
|
||||
<string name="elem_Keyboard_pin_en">If high the output D is active and one character is output.
|
||||
It also enables the clock input.</string>
|
||||
<string name="elem_Keyboard_pin_D">The last typed character, or zero if no character is available.</string>
|
||||
<string name="elem_Keyboard_pin_av">This output indicates that characters are available.
|
||||
It can be used to trigger an interrupt.</string>
|
||||
|
||||
<string name="elem_Terminal">Terminal</string>
|
||||
<string name="elem_Terminal_tt">You can write ASCII characters to this terminal.
|
||||
The terminal opens its own window to visualize the output.</string>
|
||||
@ -1417,6 +1423,7 @@
|
||||
If this is not the case, the error message of the external application is displayed.
|
||||
If possible, the input and output definitions are also adapted to the current code.</string>
|
||||
<string name="msg_applicationFileNotFound">Executable file "{0}" not found!</string>
|
||||
<string name="msg_enterText">Enter Text!</string>
|
||||
|
||||
<string name="ok">Ok</string>
|
||||
<string name="rot_0">0°</string>
|
||||
|
@ -170,7 +170,7 @@
|
||||
<visualElement>
|
||||
<elementName>Terminal</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="420" y="900"/>
|
||||
<pos x="420" y="920"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>VDD</elementName>
|
||||
@ -575,6 +575,10 @@
|
||||
<p1 x="780" y="640"/>
|
||||
<p2 x="800" y="640"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="960"/>
|
||||
<p2 x="420" y="960"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="240" y="260"/>
|
||||
<p2 x="260" y="260"/>
|
||||
@ -619,10 +623,6 @@
|
||||
<p1 x="460" y="580"/>
|
||||
<p2 x="480" y="580"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="900"/>
|
||||
<p2 x="420" y="900"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="780" y="200"/>
|
||||
<p2 x="800" y="200"/>
|
||||
@ -776,7 +776,7 @@
|
||||
<p2 x="1160" y="660"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="920"/>
|
||||
<p1 x="380" y="920"/>
|
||||
<p2 x="420" y="920"/>
|
||||
</wire>
|
||||
<wire>
|
||||
@ -923,6 +923,10 @@
|
||||
<p1 x="580" y="680"/>
|
||||
<p2 x="640" y="680"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="940"/>
|
||||
<p2 x="420" y="940"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="780" y="620"/>
|
||||
<p2 x="800" y="620"/>
|
||||
@ -959,10 +963,6 @@
|
||||
<p1 x="660" y="300"/>
|
||||
<p2 x="680" y="300"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="940"/>
|
||||
<p2 x="420" y="940"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="580" y="560"/>
|
||||
<p2 x="620" y="560"/>
|
||||
@ -995,6 +995,10 @@
|
||||
<p1 x="760" y="880"/>
|
||||
<p2 x="880" y="880"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="880"/>
|
||||
<p2 x="420" y="880"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="500"/>
|
||||
<p2 x="620" y="500"/>
|
||||
@ -1276,8 +1280,8 @@
|
||||
<p2 x="400" y="580"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="920"/>
|
||||
<p2 x="400" y="940"/>
|
||||
<p1 x="400" y="940"/>
|
||||
<p2 x="400" y="960"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="580"/>
|
||||
@ -1305,12 +1309,16 @@
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="860"/>
|
||||
<p2 x="400" y="920"/>
|
||||
<p2 x="400" y="880"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="360"/>
|
||||
<p2 x="400" y="400"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="400" y="880"/>
|
||||
<p2 x="400" y="940"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="100"/>
|
||||
<p2 x="600" y="220"/>
|
||||
@ -1653,7 +1661,7 @@
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="820"/>
|
||||
<p2 x="380" y="900"/>
|
||||
<p2 x="380" y="920"/>
|
||||
</wire>
|
||||
</wires>
|
||||
<measurementOrdering/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user