Newer
Older
IoTP / src / main / java / info / istlab / IoTP / SerialWindow.java
@motoki miura motoki miura on 26 Feb 2023 8 KB d
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.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 {

    SerialPort sp;
    JTextField jtf;
    JTextArea jta;
    Thread thread;
    
    public static Hashtable<String, SerialWindow> hash;
    static {
        hash = new Hashtable<String,SerialWindow>();
    }

    public static void check(){
        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){
            JOptionPane.showMessageDialog(null, "No available serial ports.");
        } else {
            SerialSelector.show(splist_valid.toArray(new SerialPort[]{}));
        }

    }

    public static void invoke() {
        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);
            SerialWindow sw = new SerialWindow(sp);
            hash.put(sp.getSystemPortName(), sw);    
        } else if (splist_valid.size()==0){
            JOptionPane.showMessageDialog(null, "No available serial ports.");
        } else {
            SerialSelector.show(splist_valid.toArray(new SerialPort[]{}));
        }
    }

    public SerialWindow(SerialPort _sp) {
        super("SerialMonitor " + _sp.getSystemPortName());
        sp = _sp;
        sp.setBaudRate(115200);
        sp.addDataListener(this);
        System.out.println(sp.getSystemPortName());
        if (!sp.openPort()) {
            JOptionPane.showMessageDialog(null, "他のプログラムがシリアルポート "+sp.getSystemPortName()+" を使用しています。");
            System.out.println("Unable to open the port.");
            return;
        }

        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を押すと、シリアル送信します)");
                }
            }
        });

        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.DISPOSE_ON_CLOSE);
        jtf.addActionListener(this);
        addWindowListener(this); // Xをおしたらserial closeする
    }

    @Override
    public int getListeningEvents() {
        return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
    }

    @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);
            }

        } catch (Exception ex) {
            System.err.println(ex.getMessage());
            closeSerialPort();
        }
    }

    void appendToJTA(String s) {
        if (jta == null)
            return;
        if (s.contains("waiting for download")) {
            closeSerialPort(); //切断のみ。再接続はしない
        }
        jta.append(s);
        int len = jta.getDocument().getLength();
        if (jta.getSelectedText() == null)
            jta.setCaretPosition(len);
    }

    void closeSerialPort() {
        if (sp != null) {
            if (sp.isOpen()) {
                System.out.println("close Serial Port");
                sp.closePort();
                jta.setBackground(Color.lightGray);
                // thread = new Thread(this);
                // thread.start();
            }
            // sp = null;
        }
    }

    // ここで、画面中心にウィンドウ表示するため、いろいろ計算する
    public static Point centerOfScreen(Dimension winSize) {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        return new Point((screenSize.width - winSize.width) / 2, (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();
	}

	@Override
	public void windowClosed(WindowEvent e) {
        closeSerialPort();
	}

	@Override
	public void windowIconified(WindowEvent e) {
	}

	@Override
	public void windowDeiconified(WindowEvent e) {
	}

	@Override
	public void windowActivated(WindowEvent e) {
	}

	@Override
	public void windowDeactivated(WindowEvent e) {
	}
}