Implemented generic files upload and download

master
Marco Maccaferri 2019-01-08 09:12:54 +01:00
rodzic 1790c260c6
commit 7e6073308b
2 zmienionych plików z 586 dodań i 80 usunięć

Wyświetl plik

@ -10,16 +10,25 @@
package com.maccasoft.tools;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.dialogs.ProgressIndicator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
@ -27,7 +36,12 @@ import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import com.maccasoft.tools.internal.ImageRegistry;
@ -39,7 +53,7 @@ import jssc.SerialPortException;
import jssc.SerialPortList;
import jssc.SerialPortTimeoutException;
public class SerialTerminal extends Window {
public class SerialTerminal {
public static final String[] BAUD_RATES = new String[] {
String.valueOf(SerialPort.BAUDRATE_9600),
@ -57,6 +71,7 @@ public class SerialTerminal extends Window {
public static final byte C = 0x43; // 'C' which use in XModem/CRC
Display display;
Shell shell;
Composite container;
Terminal term;
@ -64,6 +79,8 @@ public class SerialTerminal extends Window {
Combo comPort;
Combo baudRate;
ProgressIndicator progressBar;
String port;
int baud;
SerialPort serialPort;
@ -109,13 +126,100 @@ public class SerialTerminal extends Window {
}
};
final IProgressMonitor progressMonitor = new IProgressMonitor() {
@Override
public void beginTask(String name, int totalWork) {
final boolean animated = (totalWork == UNKNOWN || totalWork == 0);
display.syncExec(new Runnable() {
@Override
public void run() {
if (progressBar == null || progressBar.isDisposed()) {
return;
}
if (!progressBar.getVisible()) {
progressBar.setVisible(true);
container.layout();
}
if (!animated) {
progressBar.beginTask(totalWork);
}
else {
progressBar.beginAnimatedTask();
}
}
});
}
@Override
public void done() {
display.syncExec(new Runnable() {
@Override
public void run() {
if (progressBar == null || progressBar.isDisposed()) {
return;
}
progressBar.sendRemainingWork();
progressBar.done();
}
});
}
@Override
public void internalWorked(double work) {
display.syncExec(new Runnable() {
@Override
public void run() {
if (progressBar == null || progressBar.isDisposed()) {
return;
}
progressBar.worked(work);
}
});
}
@Override
public boolean isCanceled() {
return false;
}
@Override
public void setCanceled(boolean value) {
}
@Override
public void setTaskName(String name) {
}
@Override
public void subTask(String name) {
}
@Override
public void worked(int work) {
internalWorked(work);
}
};
public SerialTerminal() {
super((Shell) null);
}
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
public void open() {
display = Display.getDefault();
preferences = Preferences.getInstance();
shell = new Shell(display);
shell.setText(Application.APP_TITLE);
shell.setData(this);
Image[] images = new Image[] {
ImageRegistry.getImageFromResources("app128.png"),
@ -124,16 +228,146 @@ public class SerialTerminal extends Window {
ImageRegistry.getImageFromResources("app32.png"),
ImageRegistry.getImageFromResources("app16.png"),
};
newShell.setImages(images);
shell.setImages(images);
newShell.setData(this);
Menu menu = new Menu(shell, SWT.BAR);
createFileMenu(menu);
createEditMenu(menu);
createHelpMenu(menu);
shell.setMenuBar(menu);
GridLayout layout = new GridLayout(1, false);
layout.marginWidth = layout.marginHeight = 0;
shell.setLayout(layout);
Control control = createContents(shell);
control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Rectangle screen = display.getClientArea();
Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
Rectangle rect = shell.computeTrim(0, 0, size.x, size.y);
rect.x = (screen.width - rect.width) / 2;
rect.y = (screen.height - rect.height) / 2;
if (rect.y < 0) {
rect.height += rect.y * 2;
rect.y = 0;
}
shell.setLocation(rect.x, rect.y);
shell.setSize(rect.width, rect.height);
shell.open();
}
@Override
protected Control createContents(Composite parent) {
display = parent.getDisplay();
void createFileMenu(Menu parent) {
final Menu menu = new Menu(parent.getParent(), SWT.DROP_DOWN);
preferences = Preferences.getInstance();
MenuItem item = new MenuItem(parent, SWT.CASCADE);
item.setText("&File");
item.setMenu(menu);
item = new MenuItem(menu, SWT.CASCADE);
item.setText("Packed CP/M Binary Upload...");
item.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
try {
handleUploadPackedBinary();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
new MenuItem(menu, SWT.SEPARATOR);
item = new MenuItem(menu, SWT.CASCADE);
item.setText("XModem Upload...");
item.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
try {
handleUploadXModem();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
item = new MenuItem(menu, SWT.CASCADE);
item.setText("XModem Download...");
item.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
try {
handleDownloadXModem();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
new MenuItem(menu, SWT.SEPARATOR);
item = new MenuItem(menu, SWT.PUSH);
item.setText("Close");
item.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
shell.dispose();
}
});
}
void createEditMenu(Menu parent) {
Menu menu = new Menu(parent.getParent(), SWT.DROP_DOWN);
MenuItem item = new MenuItem(parent, SWT.CASCADE);
item.setText("&Edit");
item.setMenu(menu);
item = new MenuItem(menu, SWT.PUSH);
item.setText("Paste\tShift+Ins");
item.setAccelerator(SWT.MOD2 + SWT.INSERT);
item.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
try {
term.pasteFromClipboard();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
void createHelpMenu(Menu parent) {
Menu menu = new Menu(parent.getParent(), SWT.DROP_DOWN);
MenuItem item = new MenuItem(parent, SWT.CASCADE);
item.setText("&Help");
item.setMenu(menu);
item = new MenuItem(menu, SWT.PUSH);
item.setText("About " + Application.APP_TITLE);
item.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
AboutDialog dlg = new AboutDialog(shell);
dlg.open();
}
});
}
protected Control createContents(Composite parent) {
port = preferences.getSerialPort();
baud = preferences.getSerialBaud();
@ -229,6 +463,11 @@ public class SerialTerminal extends Window {
label = new Label(container, SWT.NONE);
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
progressBar = new ProgressIndicator(container, SWT.HORIZONTAL);
GridData layoutData = new GridData(GridData.GRAB_VERTICAL);
layoutData.widthHint = 128;
progressBar.setLayoutData(layoutData);
label = new Label(container, SWT.NONE);
label.setText("Port");
@ -291,7 +530,7 @@ public class SerialTerminal extends Window {
e.printStackTrace();
}
getShell().setText("Serial Terminal on " + port);
shell.setText("Serial Terminal on " + port);
}
public void setFocus() {
@ -303,13 +542,129 @@ public class SerialTerminal extends Window {
}
public void dispose() {
getShell().dispose();
shell.dispose();
}
public void uploadPackedBinary(String name, byte[] data, IProgressMonitor monitor) throws SerialPortException, SerialPortTimeoutException {
int checksum;
private void handleUploadPackedBinary() {
String s = preferences.getDownloadCommand();
final File[] fileName = getFileToOpen("Packed-Binary Upload", s != null && !s.equals(""));
if (fileName == null || fileName.length == 0) {
return;
}
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < fileName.length; i++) {
InputStream is = new FileInputStream(fileName[i]);
progressMonitor.beginTask("Upload", (is.available() + 127) / 128);
try {
uploadPackedBinary(fileName[i].getName().toUpperCase(), is, progressMonitor);
} catch (Exception e) {
e.printStackTrace();
}
progressMonitor.done();
is.close();
if ((i + 1) < fileName.length) {
try {
Thread.sleep(2000);
} catch (Exception e) {
// Do nothing
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private void handleUploadXModem() {
String s = preferences.getXmodemCommand();
final File[] fileName = getFileToOpen("XModem Upload", s != null && !s.equals(""));
if (fileName == null || fileName.length == 0) {
return;
}
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < fileName.length; i++) {
InputStream is = new FileInputStream(fileName[i]);
progressMonitor.beginTask("Upload", (is.available() + 127) / 128);
try {
uploadXModem(fileName[i].getName().toUpperCase(), is, progressMonitor);
} catch (Exception e) {
e.printStackTrace();
}
progressMonitor.done();
is.close();
if ((i + 1) < fileName.length) {
try {
Thread.sleep(2000);
} catch (Exception e) {
// Do nothing
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private File[] getFileToOpen(String text, boolean multi) {
int style = SWT.OPEN;
if (multi) {
style |= SWT.MULTI;
}
FileDialog dlg = new FileDialog(shell, style);
dlg.setText(text);
dlg.setFilterNames(new String[] {
"All Files",
"CP/M Programs"
});
dlg.setFilterExtensions(new String[] {
"*.*",
"*.COM;*.com"
});
dlg.setFilterIndex(0);
if (dlg.open() == null) {
return null;
}
String[] names = dlg.getFileNames();
File[] files = new File[names.length];
for (int i = 0; i < names.length; i++) {
files[i] = new File(dlg.getFilterPath(), names[i]);
}
return files;
}
public void uploadPackedBinary(String name, byte[] data, IProgressMonitor monitor) throws Exception {
uploadPackedBinary(name, new ByteArrayInputStream(data), monitor);
}
public void uploadPackedBinary(String name, InputStream is, IProgressMonitor monitor) throws Exception {
int data, checksum;
String s;
int length = is.available();
try {
serialPort.removeEventListener();
} catch (SerialPortException e) {
@ -317,14 +672,16 @@ public class SerialTerminal extends Window {
}
try {
s = preferences.getDownloadCommand();
s = s.replace("{0}", name.toUpperCase());
serialPort.writeString(s);
serialPort.writeInt(13);
flushOutput();
do {
s = readString();
} while (s.length() != 0 && !s.contains("DOWNLOAD "));
String cmd = preferences.getDownloadCommand();
if (cmd != null && !cmd.equals("")) {
cmd = cmd.replace("{0}", name.toUpperCase());
serialPort.writeString(cmd);
serialPort.writeInt(13);
flushOutput();
do {
s = readString();
} while (s.length() != 0 && !s.contains(cmd));
}
serialPort.writeString("U0\r");
flushOutput();
@ -343,10 +700,11 @@ public class SerialTerminal extends Window {
}
checksum = 0;
for (int i = 0; i < data.length; i++) {
serialPort.writeString(String.format("%02X", data[i] & 0xFF));
for (int i = 0; i < length; i++) {
data = is.read();
serialPort.writeString(String.format("%02X", data & 0xFF));
flushOutput();
checksum += data[i] & 0xFF;
checksum += data & 0xFF;
if (i > 0 && (i & 127) == 0) {
waitDot();
if (monitor != null) {
@ -360,7 +718,7 @@ public class SerialTerminal extends Window {
serialPort.writeString(">");
flushOutput();
if ((data.length & 127) != 0) {
if ((length & 127) != 0) {
waitDot();
if (monitor != null) {
monitor.worked(1);
@ -374,7 +732,7 @@ public class SerialTerminal extends Window {
}
}
serialPort.writeString(String.format("%02X", data.length & 0xFF));
serialPort.writeString(String.format("%02X", length & 0xFF));
flushOutput();
serialPort.writeString(String.format("%02X", checksum & 0xFF));
@ -426,8 +784,14 @@ public class SerialTerminal extends Window {
}
}
public void uploadXModem(String name, byte[] data, IProgressMonitor monitor) throws SerialPortException, SerialPortTimeoutException {
public void uploadXModem(String name, byte[] data, IProgressMonitor monitor) throws Exception {
uploadXModem(name, new ByteArrayInputStream(data), monitor);
}
public void uploadXModem(String name, InputStream is, IProgressMonitor monitor) throws Exception {
int i;
String s;
byte[] data = new byte[128];
try {
serialPort.removeEventListener();
@ -436,27 +800,29 @@ public class SerialTerminal extends Window {
}
try {
s = preferences.getXmodemCommand();
s = s.replace("{0}", name.toUpperCase());
serialPort.writeString(s);
serialPort.writeInt(13);
flushOutput();
do {
s = readString();
} while (s.length() != 0 && !s.contains("XMODEM "));
String cmd = preferences.getXmodemCommand();
if (cmd != null && !cmd.equals("")) {
cmd = cmd.replace("{0}", name.toUpperCase());
serialPort.writeString(cmd);
serialPort.writeInt(13);
flushOutput();
do {
s = readString();
} while (s.length() != 0 && !s.contains(cmd));
s = "";
while (true) {
byte[] b = serialPort.readBytes(1, 15000);
term.write(b[0]);
if (b[0] >= ' ') {
s = s + (char) b[0];
if (s.endsWith("Overwrite (Y/N)?")) {
serialPort.writeString("Y\r");
s = "";
}
if (s.endsWith("with CRCs")) {
break;
s = "";
while (true) {
byte[] b = serialPort.readBytes(1, 15000);
term.write(b[0]);
if (b[0] >= ' ') {
s = s + (char) b[0];
if (s.endsWith("Overwrite (Y/N)?")) {
serialPort.writeString("Y\r");
s = "";
}
if (s.endsWith("with CRCs")) {
break;
}
}
}
}
@ -465,8 +831,12 @@ public class SerialTerminal extends Window {
int packet = 1;
int errors = 0;
int i = 0;
while (i < data.length) {
Arrays.fill(data, (byte) 0);
if ((i = is.read(data)) < data.length) {
data[i] = 0x1A;
}
while (true) {
try {
byte[] b = serialPort.readBytes(1, 15000);
@ -480,12 +850,28 @@ public class SerialTerminal extends Window {
}
if (b[0] == ACK) {
i += 128;
packet++;
if (monitor != null) {
monitor.worked(1);
}
errors++;
errors = 0;
Arrays.fill(data, (byte) 0);
if ((i = is.read(data)) <= 0) {
serialPort.writeByte(EOT);
b = serialPort.readBytes(1, 5000);
if (b[0] == NAK) {
serialPort.writeByte(EOT);
}
b = serialPort.readBytes(1, 5000);
if (b[0] == NAK) {
serialPort.writeByte(EOT);
}
break;
}
if (i < data.length) {
data[i] = 0x1A;
}
}
if (b[0] == NAK) {
@ -501,23 +887,10 @@ public class SerialTerminal extends Window {
serialPort.writeByte((byte) (packet ^ 0xFF));
int checksum = 0, crc = 0;
int x = 0;
while (x < 128 && (i + x) < data.length) {
serialPort.writeByte(data[i + x]);
checksum += data[i + x] & 0xFF;
crc = updateCrc(crc, data[i + x] & 0xFF);
x++;
}
if (x < 128) {
serialPort.writeByte((byte) 0x1A);
checksum += 0x1A;
crc = updateCrc(crc, 0x1A);
x++;
while (x < 128) {
serialPort.writeByte((byte) 0);
crc = updateCrc(crc, 0);
x++;
}
for (int x = 0; x < data.length; x++) {
serialPort.writeByte(data[x]);
checksum += data[x] & 0xFF;
crc = updateCrc(crc, data[x] & 0xFF);
}
if (doCrc) {
@ -542,16 +915,145 @@ public class SerialTerminal extends Window {
}
}
}
} finally {
try {
serialPort.addEventListener(serialEventListener);
} catch (SerialPortException e) {
// Do nothing
}
}
}
if (i >= data.length) {
serialPort.writeByte(EOT);
byte[] b = serialPort.readBytes(1, 5000);
if (b[0] == NAK) {
serialPort.writeByte(EOT);
private void handleDownloadXModem() {
FileDialog dlg = new FileDialog(shell, SWT.SAVE);
dlg.setText("XModem Download");
dlg.setFilterNames(new String[] {
"All Files",
"CP/M Programs"
});
dlg.setFilterExtensions(new String[] {
"*.*",
"*.COM;*.com"
});
dlg.setFilterIndex(0);
dlg.setOverwrite(true);
String fileName = dlg.open();
if (fileName == null) {
return;
}
final File file = new File(fileName);
new Thread(new Runnable() {
@Override
public void run() {
try {
OutputStream os = new FileOutputStream(file);
progressMonitor.beginTask("Upload", IProgressMonitor.UNKNOWN);
try {
downloadXModem(file.getName().toUpperCase(), os, progressMonitor);
} catch (Exception e) {
e.printStackTrace();
}
progressMonitor.done();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
b = serialPort.readBytes(1, 5000);
if (b[0] == NAK) {
serialPort.writeByte(EOT);
}
}).start();
}
public void downloadXModem(String name, OutputStream os, IProgressMonitor monitor) throws Exception {
byte[] b, data, c;
try {
serialPort.removeEventListener();
} catch (SerialPortException e) {
// Do nothing
}
try {
boolean doCrc = true;
int packet = 1;
int errors = 0;
serialPort.writeByte(doCrc ? C : NAK);
while (true) {
try {
b = serialPort.readBytes(1, 15000);
if (b[0] == SOH) {
b = serialPort.readBytes(2, 15000);
data = serialPort.readBytes(128, 15000);
c = serialPort.readBytes(doCrc ? 2 : 1, 15000);
if (b[0] != (byte) packet || (b[0] ^ b[1]) != (byte) 0xFF) {
serialPort.writeByte(NAK);
errors++;
if (errors >= 10) {
return;
}
continue;
}
int checksum = 0, crc = 0;
for (int x = 0; x < data.length; x++) {
checksum += data[x] & 0xFF;
crc = updateCrc(crc, data[x] & 0xFF);
}
if (doCrc) {
if (c[0] != (byte) (crc >> 8) || c[1] != (byte) (crc & 0xFF)) {
serialPort.writeByte(NAK);
errors++;
if (errors >= 10) {
return;
}
continue;
}
}
else {
if (c[0] != (byte) (checksum & 0xFF)) {
serialPort.writeByte(NAK);
errors++;
if (errors >= 10) {
return;
}
continue;
}
}
os.write(data);
serialPort.writeByte(ACK);
packet++;
errors = 0;
}
else if (b[0] == EOT) {
serialPort.writeByte(ACK);
break;
}
if (monitor != null && monitor.isCanceled()) {
serialPort.writeBytes(new byte[] {
CAN, CAN, CAN
});
return;
}
} catch (SerialPortTimeoutException e) {
errors++;
if (errors >= 10) {
return;
}
if (doCrc && errors >= 5) {
doCrc = false;
errors = 0;
}
serialPort.writeByte(doCrc ? C : NAK);
}
}
} finally {
@ -575,6 +1077,10 @@ public class SerialTerminal extends Window {
return crc & 0xFFFF;
}
public Shell getShell() {
return shell;
}
static {
System.setProperty("SWT_GTK3", "0");
}

Wyświetl plik

@ -356,7 +356,7 @@ public class Terminal {
}
}
void pasteFromClipboard() {
public void pasteFromClipboard() {
Clipboard clipboard = new Clipboard(display);
try {
String s = (String) clipboard.getContents(TextTransfer.getInstance());