mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-18 09:24:42 -04:00
stdio interface is working
This commit is contained in:
parent
b44c92c379
commit
11ded0ca3b
@ -84,7 +84,7 @@ public class External extends Node implements Element {
|
|||||||
@Override
|
@Override
|
||||||
public void writeOutputs() throws NodeException {
|
public void writeOutputs() throws NodeException {
|
||||||
try {
|
try {
|
||||||
processHandler.readValuesTo(outputs);
|
processHandler.readValues(outputs);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new NodeException(Lang.get("err_errorReadingDataToProcess"), this, -1, outputs, e);
|
throw new NodeException(Lang.get("err_errorReadingDataToProcess"), this, -1, outputs, e);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package de.neemann.digital.core.extern;
|
package de.neemann.digital.core.extern;
|
||||||
|
|
||||||
|
import de.neemann.digital.core.extern.handler.Generic;
|
||||||
import de.neemann.digital.lang.Lang;
|
import de.neemann.digital.lang.Lang;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -43,6 +44,8 @@ public final class ProcessFactory {
|
|||||||
*/
|
*/
|
||||||
public static ProcessHandler create(Type type, String code, String params) throws IOException {
|
public static ProcessHandler create(Type type, String code, String params) throws IOException {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case Generic:
|
||||||
|
return new Generic(params);
|
||||||
default:
|
default:
|
||||||
throw new IOException(Lang.get("err_processType_N_notFound", type.name()));
|
throw new IOException(Lang.get("err_processType_N_notFound", type.name()));
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,6 @@ public interface ProcessHandler extends Closeable {
|
|||||||
* @param values the values to write to
|
* @param values the values to write to
|
||||||
* @throws IOException IOException
|
* @throws IOException IOException
|
||||||
*/
|
*/
|
||||||
void readValuesTo(ObservableValues values) throws IOException;
|
void readValues(ObservableValues values) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
24
src/main/java/de/neemann/digital/core/extern/handler/Generic.java
vendored
Normal file
24
src/main/java/de/neemann/digital/core/extern/handler/Generic.java
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 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.core.extern.handler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the string given in params as an external application
|
||||||
|
*/
|
||||||
|
public class Generic extends StdIOProcess {
|
||||||
|
/**
|
||||||
|
* Creates a new simple process
|
||||||
|
*
|
||||||
|
* @param name the name of the application to start
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public Generic(String name) throws IOException {
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(name);
|
||||||
|
setProcess(pb.start());
|
||||||
|
}
|
||||||
|
}
|
@ -10,24 +10,29 @@ import de.neemann.digital.core.ObservableValues;
|
|||||||
import de.neemann.digital.core.extern.ProcessHandler;
|
import de.neemann.digital.core.extern.ProcessHandler;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The generic process description
|
* The generic process description
|
||||||
*/
|
*/
|
||||||
public abstract class StdIOProcess implements ProcessHandler {
|
public class StdIOProcess implements ProcessHandler {
|
||||||
|
private static final String PREFIX = "digital:";
|
||||||
|
private Process process;
|
||||||
private BufferedWriter writer;
|
private BufferedWriter writer;
|
||||||
private BufferedReader reader;
|
private Thread thread;
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private String dataFound;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the reader and writer
|
* Set the already started process
|
||||||
*
|
*
|
||||||
* @param reader the reader
|
* @param process the process to use
|
||||||
* @param writer the writer
|
|
||||||
*/
|
*/
|
||||||
public void setReaderWriter(BufferedReader reader, BufferedWriter writer) {
|
public void setProcess(Process process) {
|
||||||
this.reader = reader;
|
this.process = process;
|
||||||
this.writer = writer;
|
setInputOutputStream(process.getInputStream(), process.getOutputStream());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,58 +41,142 @@ public abstract class StdIOProcess implements ProcessHandler {
|
|||||||
* @param in the input stream
|
* @param in the input stream
|
||||||
* @param out the output stream
|
* @param out the output stream
|
||||||
*/
|
*/
|
||||||
public void setInputOutputStream(InputStream in, OutputStream out) {
|
private void setInputOutputStream(InputStream in, OutputStream out) {
|
||||||
setReaderWriter(
|
setReaderWriter(
|
||||||
new BufferedReader(new InputStreamReader(in)),
|
new BufferedReader(new InputStreamReader(in)),
|
||||||
new BufferedWriter(new OutputStreamWriter(out)));
|
new BufferedWriter(new OutputStreamWriter(out)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reader and writer
|
||||||
|
*
|
||||||
|
* @param reader the reader
|
||||||
|
* @param writer the writer
|
||||||
|
*/
|
||||||
|
private void setReaderWriter(BufferedReader reader, BufferedWriter writer) {
|
||||||
|
this.writer = writer;
|
||||||
|
|
||||||
|
thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if (line.startsWith(PREFIX)) {
|
||||||
|
synchronized (lock) {
|
||||||
|
while (dataFound != null)
|
||||||
|
lock.wait();
|
||||||
|
dataFound = line;
|
||||||
|
lock.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.setDaemon(true);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readLine() throws IOException {
|
||||||
|
synchronized (lock) {
|
||||||
|
try {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
while (dataFound == null && (System.currentTimeMillis() - startTime) < 5000)
|
||||||
|
lock.wait(1000);
|
||||||
|
|
||||||
|
if (dataFound == null)
|
||||||
|
throw new IOException("timeout");
|
||||||
|
|
||||||
|
String line = dataFound;
|
||||||
|
dataFound = null;
|
||||||
|
lock.notify();
|
||||||
|
|
||||||
|
return line;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeValues(ObservableValues values) throws IOException {
|
public void writeValues(ObservableValues values) throws IOException {
|
||||||
boolean first = true;
|
|
||||||
for (ObservableValue v : values) {
|
for (ObservableValue v : values) {
|
||||||
if (first)
|
final int bits = v.getBits();
|
||||||
first = false;
|
final long value = v.getValue();
|
||||||
else
|
final long highZ = v.getHighZ();
|
||||||
writer.write(",");
|
long mask = 1;
|
||||||
writer.write(v.getName());
|
for (int i = 0; i < bits; i++) {
|
||||||
writer.write("=");
|
if ((highZ & mask) != 0)
|
||||||
writer.write(Long.toHexString(v.getValue()));
|
writer.write('Z');
|
||||||
|
else {
|
||||||
|
if ((value & mask) != 0)
|
||||||
|
writer.write('1');
|
||||||
|
else
|
||||||
|
writer.write('0');
|
||||||
|
}
|
||||||
|
mask <<= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writer.write("\n");
|
writer.write("\n");
|
||||||
writer.flush();
|
writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readValuesTo(ObservableValues values) throws IOException {
|
public void readValues(ObservableValues values) throws IOException {
|
||||||
String line;
|
String line = readLine();
|
||||||
while ((line = reader.readLine()) != null) {
|
if (line != null) {
|
||||||
if (line.startsWith("digital:")) {
|
int pos = PREFIX.length();
|
||||||
StringTokenizer st = new StringTokenizer(line.substring(8), ",=", true);
|
int len = line.length();
|
||||||
for (ObservableValue v : values) {
|
for (ObservableValue v : values) {
|
||||||
if (!st.hasMoreTokens())
|
final int bits = v.getBits();
|
||||||
throw new IOException("not enough values received!");
|
|
||||||
|
|
||||||
String name = st.nextToken().trim();
|
if (pos + bits > len)
|
||||||
if (name.equals(","))
|
throw new IOException("not enough data");
|
||||||
name = st.nextToken().trim();
|
|
||||||
|
|
||||||
if (!name.equals(v.getName()))
|
|
||||||
throw new IOException("values in wrong order: expected " + v.getName() + " but found " + name);
|
|
||||||
|
|
||||||
if (!st.nextToken().equals("="))
|
|
||||||
throw new IOException("= expected");
|
|
||||||
|
|
||||||
final String valStr = st.nextToken();
|
|
||||||
if (valStr.equals("Z"))
|
|
||||||
v.setToHighZ();
|
|
||||||
else
|
|
||||||
v.setValue(Long.parseLong(valStr, 16));
|
|
||||||
|
|
||||||
|
long value = 0;
|
||||||
|
long highZ = 0;
|
||||||
|
long mask = 1;
|
||||||
|
for (int i = 0; i < bits; i++) {
|
||||||
|
char c = line.charAt(pos);
|
||||||
|
switch (c) {
|
||||||
|
case 'z':
|
||||||
|
case 'Z':
|
||||||
|
highZ |= mask;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
case '1':
|
||||||
|
value |= mask;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
case 'L':
|
||||||
|
case '0':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IOException("invalid character " + c);
|
||||||
|
}
|
||||||
|
mask <<= 1;
|
||||||
|
pos++;
|
||||||
}
|
}
|
||||||
return;
|
v.set(value, highZ);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
throw new IOException("process has stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
process.destroy();
|
||||||
|
|
||||||
|
thread.interrupt();
|
||||||
|
|
||||||
|
try {
|
||||||
|
thread.join(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IOException("thread was interrupted");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread.isAlive())
|
||||||
|
throw new IOException("thread was not stopped");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user