mirror of
https://github.com/badvision/jace.git
synced 2025-02-17 08:30:53 +00:00
Revamp of SSC port handling
This commit is contained in:
parent
3bca1f29c0
commit
52e07ebd54
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package jace.hardware;
|
package jace.hardware;
|
||||||
|
|
||||||
|
import jace.EmulatorUILogic;
|
||||||
import jace.config.ConfigurableField;
|
import jace.config.ConfigurableField;
|
||||||
import jace.config.Name;
|
import jace.config.Name;
|
||||||
import jace.config.Reconfigurable;
|
import jace.config.Reconfigurable;
|
||||||
@ -26,15 +27,16 @@ import jace.core.Computer;
|
|||||||
import jace.core.RAMEvent;
|
import jace.core.RAMEvent;
|
||||||
import jace.core.RAMEvent.TYPE;
|
import jace.core.RAMEvent.TYPE;
|
||||||
import jace.core.Utility;
|
import jace.core.Utility;
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Super Serial Card with serial-over-tcp/ip support. This is fully compatible
|
* Super Serial Card with serial-over-tcp/ip support. This is fully compatible
|
||||||
@ -43,12 +45,13 @@ import javax.swing.ImageIcon;
|
|||||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||||
*/
|
*/
|
||||||
@Name("Super Serial Card")
|
@Name("Super Serial Card")
|
||||||
public class CardSSC extends Card implements Reconfigurable, Runnable {
|
public class CardSSC extends Card implements Reconfigurable {
|
||||||
|
|
||||||
@ConfigurableField(name = "TCP/IP Port", shortName = "port")
|
@ConfigurableField(name = "TCP/IP Port", shortName = "port")
|
||||||
public static short IP_PORT = 1977;
|
public short IP_PORT = 1977;
|
||||||
protected ServerSocket socket;
|
protected ServerSocket socket;
|
||||||
protected Socket clientSocket;
|
protected Socket clientSocket;
|
||||||
|
protected BufferedReader socketInput;
|
||||||
protected Thread listenThread;
|
protected Thread listenThread;
|
||||||
private int lastInputByte = 0;
|
private int lastInputByte = 0;
|
||||||
private boolean FULL_ECHO = true;
|
private boolean FULL_ECHO = true;
|
||||||
@ -82,7 +85,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
// 1 stop bit (SW2-1 on)
|
// 1 stop bit (SW2-1 on)
|
||||||
// 8 data bits (SW2-2 on)
|
// 8 data bits (SW2-2 on)
|
||||||
// No parity (SW2-3 don't care, SW2-4 off)
|
// No parity (SW2-3 don't care, SW2-4 off)
|
||||||
private static int SW2_SETTING = 0x04;
|
private int SW2_SETTING = 0x04;
|
||||||
public int ACIA_Data = 0x08; // Read=Receive / Write=transmit
|
public int ACIA_Data = 0x08; // Read=Receive / Write=transmit
|
||||||
public int ACIA_Status = 0x09; // Read=Status / Write=Reset
|
public int ACIA_Status = 0x09; // Read=Status / Write=Reset
|
||||||
public int ACIA_Command = 0x0A;
|
public int ACIA_Command = 0x0A;
|
||||||
@ -117,24 +120,28 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
activityIndicator.setText("Slot " + slot);
|
activityIndicator.setText("Slot " + slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
boolean newInputAvailable = false;
|
||||||
public void run() {
|
public void socketMonitor() {
|
||||||
while (socket != null && !socket.isClosed()) {
|
while (socket != null && !socket.isClosed()) {
|
||||||
try {
|
try {
|
||||||
Logger.getLogger(CardSSC.class.getName()).log(Level.INFO, "Slot " + getSlot() + " listening on port " + IP_PORT, (Throwable) null);
|
Logger.getLogger(CardSSC.class.getName()).log(Level.INFO, "Slot " + getSlot() + " listening on port " + IP_PORT, (Throwable) null);
|
||||||
// System.out.println("Waiting for connect");
|
|
||||||
while ((clientSocket = socket.accept()) != null) {
|
while ((clientSocket = socket.accept()) != null) {
|
||||||
|
socketInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
|
||||||
clientConnected();
|
clientConnected();
|
||||||
clientSocket.setTcpNoDelay(true);
|
clientSocket.setTcpNoDelay(true);
|
||||||
while (isConnected()) {
|
while (isConnected()) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(livenessCheck / 2);
|
Thread.sleep(10);
|
||||||
|
if (socketInput.ready()) {
|
||||||
|
newInputAvailable = true;
|
||||||
|
}
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clientDisconnected();
|
clientDisconnected();
|
||||||
hangUp();
|
hangUp();
|
||||||
|
socketInput = null;
|
||||||
}
|
}
|
||||||
} catch (SocketTimeoutException ex) {
|
} catch (SocketTimeoutException ex) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
@ -148,6 +155,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
// Called when a client first connects via telnet
|
// Called when a client first connects via telnet
|
||||||
public void clientConnected() {
|
public void clientConnected() {
|
||||||
System.err.println("Client connected");
|
System.err.println("Client connected");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when a client disconnects
|
// Called when a client disconnects
|
||||||
@ -179,10 +187,16 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
java.awt.EventQueue.invokeLater(() -> {
|
Thread resetThread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(50);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Logger.getLogger(CardSSC.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
suspend();
|
suspend();
|
||||||
resume();
|
resume();
|
||||||
});
|
});
|
||||||
|
resetThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -203,11 +217,8 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
newValue |= (PORT_CONNECTED && inputAvailable()) ? 0x00 : 0x01;
|
newValue |= (PORT_CONNECTED && inputAvailable()) ? 0x00 : 0x01;
|
||||||
}
|
}
|
||||||
if (register == ACIA_Data) {
|
if (register == ACIA_Data) {
|
||||||
// Emulator.getFrame().addIndicator(this, activityIndicator);
|
EmulatorUILogic.addIndicator(this, activityIndicator);
|
||||||
newValue = getInputByte();
|
newValue = getInputByte();
|
||||||
if (RECV_IRQ_ENABLED) {
|
|
||||||
triggerIRQ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (register == ACIA_Status) {
|
if (register == ACIA_Status) {
|
||||||
newValue = 0;
|
newValue = 0;
|
||||||
@ -215,13 +226,11 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
// 1 = Framing error (1)
|
// 1 = Framing error (1)
|
||||||
// 2 = Overrun error (1)
|
// 2 = Overrun error (1)
|
||||||
// 3 = ACIA Receive Register full (1)
|
// 3 = ACIA Receive Register full (1)
|
||||||
if (inputAvailable()) {
|
if (newInputAvailable || inputAvailable()) {
|
||||||
newValue |= 0x08;
|
newValue |= 0x08;
|
||||||
}
|
}
|
||||||
// 4 = ACIA Transmit Register empty (1)
|
// 4 = ACIA Transmit Register empty (1)
|
||||||
if (true) {
|
|
||||||
newValue |= 0x010;
|
newValue |= 0x010;
|
||||||
}
|
|
||||||
// 5 = Data Carrier Detect (DCD) true (0)
|
// 5 = Data Carrier Detect (DCD) true (0)
|
||||||
// 6 = Data Set Ready (DSR) true (0)
|
// 6 = Data Set Ready (DSR) true (0)
|
||||||
// 7 = Interrupt (IRQ) has occurred
|
// 7 = Interrupt (IRQ) has occurred
|
||||||
@ -231,7 +240,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
IRQ_TRIGGERED = false;
|
IRQ_TRIGGERED = false;
|
||||||
}
|
}
|
||||||
if (register == ACIA_Command) {
|
if (register == ACIA_Command) {
|
||||||
newValue = 0;
|
newValue = DTR ? 1 : 0;
|
||||||
// 0 = DTR Enable (1) / Disable (0) receiver and IRQ
|
// 0 = DTR Enable (1) / Disable (0) receiver and IRQ
|
||||||
// 1 = Allow IRQ (1) when status bit 3 is true
|
// 1 = Allow IRQ (1) when status bit 3 is true
|
||||||
if (RECV_IRQ_ENABLED) {
|
if (RECV_IRQ_ENABLED) {
|
||||||
@ -255,7 +264,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
break;
|
break;
|
||||||
case WRITE:
|
case WRITE:
|
||||||
if (register == ACIA_Data) {
|
if (register == ACIA_Data) {
|
||||||
// Emulator.getFrame().addIndicator(this, activityIndicator);
|
EmulatorUILogic.addIndicator(this, activityIndicator);
|
||||||
sendOutputByte(value & 0x0FF);
|
sendOutputByte(value & 0x0FF);
|
||||||
if (TRANS_IRQ_ENABLED) {
|
if (TRANS_IRQ_ENABLED) {
|
||||||
triggerIRQ();
|
triggerIRQ();
|
||||||
@ -295,7 +304,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
}
|
}
|
||||||
// 4 = Normal mode 0, or Echo mode 1 (bits 2 and 3 must be 0)
|
// 4 = Normal mode 0, or Echo mode 1 (bits 2 and 3 must be 0)
|
||||||
FULL_ECHO = ((value & 16) > 0);
|
FULL_ECHO = ((value & 16) > 0);
|
||||||
System.out.println("Echo set to " + FULL_ECHO);
|
// System.out.println("Echo set to " + FULL_ECHO);
|
||||||
// 5 = Control parity
|
// 5 = Control parity
|
||||||
}
|
}
|
||||||
if (register == ACIA_Control) {
|
if (register == ACIA_Control) {
|
||||||
@ -326,7 +335,6 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
e.setNewValue(newValue);
|
e.setNewValue(newValue);
|
||||||
value = newValue;
|
value = newValue;
|
||||||
}
|
}
|
||||||
// System.out.println("SSC I/O "+type+", register "+register+", value "+value);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
Logger.getLogger(CardSSC.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(CardSSC.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
@ -334,12 +342,16 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
// Do nothing
|
if (RECV_IRQ_ENABLED && newInputAvailable) {
|
||||||
|
newInputAvailable = false;
|
||||||
|
triggerIRQ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean inputAvailable() throws IOException {
|
public boolean inputAvailable() throws IOException {
|
||||||
if (isConnected() && clientSocket != null && clientSocket.getInputStream() != null) {
|
if (isConnected() && clientSocket != null && socketInput != null) {
|
||||||
return clientSocket.getInputStream().available() > 0;
|
// return socketInput.available() > 0;
|
||||||
|
return socketInput.ready();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -347,13 +359,10 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
|
|
||||||
private int getInputByte() throws IOException {
|
private int getInputByte() throws IOException {
|
||||||
if (inputAvailable()) {
|
if (inputAvailable()) {
|
||||||
int in = clientSocket.getInputStream().read() & DATA_BITS;
|
int in = socketInput.read() & DATA_BITS;
|
||||||
// System.out.write(in & 0x07f);
|
|
||||||
if (RECV_STRIP_LF && in == 10 && lastInputByte == 13) {
|
if (RECV_STRIP_LF && in == 10 && lastInputByte == 13) {
|
||||||
in = clientSocket.getInputStream().read() & DATA_BITS;
|
in = socketInput.read() & DATA_BITS;
|
||||||
// System.out.write(in & 0x07f);
|
|
||||||
}
|
}
|
||||||
// System.out.flush();
|
|
||||||
lastInputByte = in;
|
lastInputByte = in;
|
||||||
}
|
}
|
||||||
return lastInputByte;
|
return lastInputByte;
|
||||||
@ -363,10 +372,8 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
private void sendOutputByte(int i) throws IOException {
|
private void sendOutputByte(int i) throws IOException {
|
||||||
if (clientSocket != null && clientSocket.isConnected()) {
|
if (clientSocket != null && clientSocket.isConnected()) {
|
||||||
try {
|
try {
|
||||||
// System.out.write(i & 0x07f);
|
|
||||||
clientSocket.getOutputStream().write(i & DATA_BITS);
|
clientSocket.getOutputStream().write(i & DATA_BITS);
|
||||||
if (TRANS_ADD_LF && (i & DATA_BITS) == 13) {
|
if (TRANS_ADD_LF && (i & DATA_BITS) == 13) {
|
||||||
// System.out.write(10);
|
|
||||||
clientSocket.getOutputStream().write(10);
|
clientSocket.getOutputStream().write(10);
|
||||||
}
|
}
|
||||||
clientSocket.getOutputStream().flush();
|
clientSocket.getOutputStream().flush();
|
||||||
@ -419,6 +426,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean suspend() {
|
public boolean suspend() {
|
||||||
|
synchronized (this) {
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
@ -438,9 +446,12 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
socket = null;
|
socket = null;
|
||||||
return super.suspend();
|
return super.suspend();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resume() {
|
public void resume() {
|
||||||
|
synchronized (this) {
|
||||||
|
|
||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
super.resume();
|
super.resume();
|
||||||
RECV_IRQ_ENABLED = false;
|
RECV_IRQ_ENABLED = false;
|
||||||
@ -452,9 +463,9 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
socket.setReuseAddress(true);
|
socket.setReuseAddress(true);
|
||||||
socket.setSoTimeout(0);
|
socket.setSoTimeout(0);
|
||||||
//socket.setReuseAddress(true);
|
//socket.setReuseAddress(true);
|
||||||
listenThread = new Thread(this);
|
listenThread = new Thread(this::socketMonitor);
|
||||||
listenThread.setDaemon(false);
|
listenThread.setDaemon(false);
|
||||||
listenThread.setName("SSC port listener");
|
listenThread.setName("SSC port listener, slot" + getSlot());
|
||||||
listenThread.start();
|
listenThread.start();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
suspend();
|
suspend();
|
||||||
@ -462,6 +473,7 @@ public class CardSSC extends Card implements Reconfigurable, Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@ConfigurableField(category = "Advanced", name = "Liveness check interval", description = "How often the connection is polled for signs of life (in milliseconds)")
|
@ConfigurableField(category = "Advanced", name = "Liveness check interval", description = "How often the connection is polled for signs of life (in milliseconds)")
|
||||||
public int livenessCheck = 10000;
|
public int livenessCheck = 10000;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user