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 || 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 openAll() { if (serialChecker == null) serialChecker = Launcher.theapp.serialChecker; serialChecker.portHash.entrySet().forEach(ent -> { String key = ent.getKey(); SerialPort sp = ent.getValue(); if (hash.get(key) != null) { SerialWindow swin = hash.get(key); swin.setVisible(true); swin.reconnect(); } else { new SerialWindow(sp); } }); } 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) { } }