package info.istlab.IoTP;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.Hashtable;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
public class SerialWindow extends JFrame
implements SerialPortDataListener, ActionListener, Runnable, WindowListener, KeyListener {
SerialPort sp;
JTextField jtf;
JTextArea jta;
Thread thread;
static SerialChecker serialChecker;
public static Hashtable<String, SerialWindow> hash;
static {
hash = new Hashtable<String, SerialWindow>();
}
/**
* チェックして、App.serialName にポート名をセットするだけ。
*/
public static void check(boolean popup_if_zero) {
if (App.serialName == null) {
if (serialChecker == null)
serialChecker = Launcher.theapp.serialChecker;
serialChecker.updateSerialNames();
}
if (serialChecker.validSerialNames.size() == 0) {
if (popup_if_zero)
JOptionPane.showMessageDialog(Launcher.theapp, "No available serial ports.");
}
// SerialPort[] ports = SerialPort.getCommPorts();
// ArrayList<SerialPort> splist_valid = new ArrayList<SerialPort>();
// for (SerialPort sp : ports) {
// String name = sp.getSystemPortName();
// if (name.startsWith("cu.usbserial") || name.startsWith("COM")) {
// splist_valid.add(sp);
// }
// }
// if (splist_valid.size() == 1) {
// SerialPort sp = splist_valid.get(0);
// App.serialName = sp.getSystemPortName();
// } else if (splist_valid.size() == 0) {
// if (popup_if_zero)
// JOptionPane.showMessageDialog(Launcher.theapp, "No available serial ports.");
// } else {
// if (App.serialName == null) SerialSelector.show(splist_valid.toArray(new
// SerialPort[] {}));
// }
}
public static void invoke(boolean popup_if_zero) {
if (serialChecker == null)
serialChecker = Launcher.theapp.serialChecker;
serialChecker.updateSerialNames();
if (serialChecker.validSerialNames.size() == 0) {
if (popup_if_zero)
JOptionPane.showMessageDialog(Launcher.theapp, "No available serial ports.");
return;
}
SerialWindow swin = hash.get(App.serialName);
if (swin == null) {
SerialPort sp = serialChecker.portHash.get(App.serialName);
swin = new SerialWindow(sp);
} else {
swin.setVisible(true);
swin.reconnect();
}
// SerialPort[] ports = SerialPort.getCommPorts();
// ArrayList<SerialPort> splist_valid = new ArrayList<SerialPort>();
// for (SerialPort sp : ports) {
// String name = sp.getSystemPortName();
// if (name.startsWith("cu.usbserial") || name.startsWith("COM")) {
// splist_valid.add(sp);
// }
// }
// if (splist_valid.size() == 1) {
// SerialPort sp = splist_valid.get(0);
// new SerialWindow(sp);
// } else if (splist_valid.size() == 0) {
// JOptionPane.showMessageDialog(Launcher.theapp, "No available serial ports.");
// } else {
// if (App.serialName == null) SerialSelector.show(splist_valid.toArray(new
// SerialPort[] {}));
// SerialPort sp = Launcher.theapp.serialChecker.portHash.get(App.serialName);
// new SerialWindow(sp);
// }
}
public SerialWindow(SerialPort _sp) {
super("SerialMonitor " + _sp.getSystemPortName() + " (ボーレート:115200)");
sp = _sp;
sp.setBaudRate(115200);
sp.addDataListener(this);
System.out.println(sp.getSystemPortName());
if (!sp.openPort()) {
JOptionPane.showMessageDialog(Launcher.theapp,
"他のウィンドウまたはプログラムがシリアルポート " + sp.getSystemPortName() + " を使用しています。");
System.out.println("Unable to open the port.");
return;
}
hash.put(sp.getSystemPortName(), this);
jtf = new JTextField("(ここをクリックして、入力して、Enterを押すと、シリアル送信します)");
jtf.setForeground(Color.GRAY);
jtf.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (jtf.getText().equals("(ここをクリックして、入力して、Enterを押すと、シリアル送信します)")) {
jtf.setText("");
jtf.setForeground(Color.BLACK);
}
}
@Override
public void focusLost(FocusEvent e) {
if (jtf.getText().isEmpty()) {
jtf.setForeground(Color.GRAY);
jtf.setText("(ここをクリックして、入力して、Enterを押すと、シリアル送信します)");
}
}
});
jtf.setBackground(new Color(210, 255, 255));
getContentPane().add(jtf, BorderLayout.NORTH);
jta = new JTextArea();
getContentPane().add(new JScrollPane(jta), BorderLayout.CENTER);
// compileB = new JButton("compile");
// compileB.addActionListener(e -> {
// compile(e.getActionCommand());
// });
// getContentPane().add(compileB, BorderLayout.SOUTH);
setSize(500, 400);
setLocation(centerOfScreen(getSize()));
setVisible(true);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // この下のWindowListenerで処理する
jtf.addActionListener(this);
addWindowListener(this); // Xをおしたらserial closeする
// フォーカスをあえて外す
jta.requestFocus();
jtf.addKeyListener(this);
jta.addKeyListener(this);
}
@Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE | SerialPort.LISTENING_EVENT_PORT_DISCONNECTED;
}
@Override
public void serialEvent(SerialPortEvent event) {
try {
int evt = event.getEventType();
// System.out.println("Event " + evt + " received");
if (evt == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
int bytesToRead = sp.bytesAvailable();
if (bytesToRead == -1) {
System.out.println("-1 means port is closed.");
closeSerialPort("切断されました");
return;
}
byte[] newData = new byte[bytesToRead];
sp.readBytes(newData, bytesToRead);
String s = new String(newData, "UTF8");
appendToJTA(s);
} else if (evt == SerialPort.LISTENING_EVENT_PORT_DISCONNECTED) {
System.out.println("Port disconnected.");
// System.out.println(event.toString());
closeSerialPort("切断されました");
// SerialWindow.closeAll("切断されました");
}
} catch (Exception ex) {
System.err.println(ex.getMessage());
closeSerialPort("切断されました");
}
}
void appendToJTA(String s) {
if (jta == null)
return;
if (s.contains("waiting for download")) {
closeSerialPort(null); // 切断のみ。再接続はしない
}
jta.append(s);
int len = jta.getDocument().getLength();
if (jta.getSelectedText() == null)
jta.setCaretPosition(len);
}
// ここで、画面中心にウィンドウ表示するため、いろいろ計算する
public static Point centerOfScreen(Dimension winSize) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
return new Point((screenSize.width - winSize.width) / 2, (screenSize.height - winSize.height) / 2);
}
// ここで、画面中心にウィンドウ表示するため、いろいろ計算する
public static Point leftOfScreen(Dimension winSize) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
return new Point(10, (screenSize.height - winSize.height) / 2);
}
@Override
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
System.out.println(action);
try {
String message = action + "\n";
byte[] b = message.getBytes();
System.out.println("send " + b.length + " bytes");
sp.writeBytes(b, b.length);
jtf.setText("");
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
/**
* 再接続用(つかっていない)
*/
@Override
public void run() {
appendToJTA("(Waiting to reconnect.)\n");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
while (thread != null) {
if (!sp.openPort()) {
System.out.println("Unable to open the port.");
return;
} else {
thread = null;
appendToJTA("Reconnected.\n");
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
// closeSerialPort("シリアルモニタウィンドウを閉じます");
disposeWin();
}
@Override
public void windowClosed(WindowEvent e) {
disposeWin();
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
public static void disposeAll() {
ArrayList<SerialWindow> toberemoved = new ArrayList<SerialWindow>();
SerialWindow.hash.entrySet().forEach(ent -> {
// String key = ent.getKey();
SerialWindow swin = ent.getValue();
if (swin != null) {
toberemoved.add(swin);
}
});
for (SerialWindow swin : toberemoved) {
swin.disposeWin();
}
// SerialWindow.hash.clear();
}
public static void disposeByName(String serialName) {
for (String key : SerialWindow.hash.keySet()) {
if (!key.equals(serialName))
continue;
SerialWindow swin = SerialWindow.hash.get(key);
if (swin != null) {
swin.disposeWin();
}
}
}
// public static void closeAll(String mes) {
// for (String key : SerialWindow.hash.keySet()) {
// SerialWindow swin = SerialWindow.hash.get(key);
// if (swin != null) {
// if (mes == null)
// mes = "Uploadに備え、切断しました";
// swin.closeSerialPort(mes);
// }
// }
// }
/**
* シリアルポート接続を閉じる
*
* @param mes
*/
void closeSerialPort(String mes) {
if (sp != null) {
if (sp.isOpen()) {
System.out.println("close Serial Port");
sp.closePort();
jta.setBackground(Color.lightGray);
if (mes == null)
appendToJTA("Uploadに備えて、切断しました。");
else
appendToJTA(mes);
}
}
// 再接続に備えて、sp = null はしない
}
/**
* 再接続
*/
public void reconnect() {
sp.openPort();
jta.setBackground(Color.white);
}
/**
* ウィンドウを閉じる前に、シリアルポート接続を閉じる
*/
public void disposeWin() {
closeSerialPort("シリアルモニタウィンドウを閉じます");
SerialWindow.hash.remove(this.sp.getSystemPortName());
dispose();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.isControlDown() || e.isAltDown() || e.isAltGraphDown() || e.isMetaDown()) {
if (e.getKeyCode() == 87) { // W
closeSerialPort("シリアルモニタウィンドウを閉じます");
disposeWin();
}
}
}
@Override
public void keyReleased(KeyEvent e) {
}
}