天天看點

樹莓派3使用JAVA實作序列槽通訊

樹莓派3使用JAVA實作序列槽通訊

1、配置樹莓派:

(1)sudo raspi-config

(2)選擇 Interfacing Options,然後選擇Serial,關閉序列槽shell終端,使能序列槽。

(3)修改配置檔案

sudo nano /boot/config.txt

追加如下内容

dtoverlay=pi3-miniuart-bt
enable_uart=1
           

2、配置Java序列槽環境

(1)擷取系統版本資訊

uname -r

(2)将擷取到的系統版本資訊寫入配置檔案/usr/include/linux/version.h

(3)下載下傳相關程式包【網頁連結:http://rxtx.qbang.org/wiki/index.php/Download】

wget http://rxtx.qbang.org/pub/rxtx/rxtx-2.2pre2.zip

unzip rxtx-2.2pre2.zip

cd rxtx-2.2pre2

(4)JDK1.6及以上的運作環境下,需要對configure檔案進行修改。

在configure檔案中找到所有的 1.2*|1.3*|1.4*|1.5* , 将現有的JDK版本加入進去即可.如:改成 1.2*|1.3*|1.4*|1.5*|1.6*|1.7*|1.8*
           

sh ./configure

make

make install

(5)安裝成功後,會顯示如下資訊

Libraries have been installed in:
/cloud/jdk/jre/lib/arm
...................
/usr/bin/install -c RXTXcomm.jar /cloud/jdk/jre/lib/ext/
           

3、編寫java代碼

示例代碼如下

/**
 * 序列槽通訊
 */
public class SerialPortManager
{
    private static final SerialPortManager SERIAL_PORT_MANAGER = new SerialPortManager();
    private SerialPort serialPort;
    private InputStream inputStream;
    private OutputStream outputStream;

    public static SerialPortManager getInstance()
    {
        return SERIAL_PORT_MANAGER;
    }

    public void init()
    {
        if (openPort())//打開序列槽
        {
            addListener();//添加監聽器
            return;
        }
        Device.isConnect = false;
        try
        {
            Thread.sleep(2000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        //重新整理參數
        new ParameterManager(false).run();
    }

    /**
     * 從序列槽讀取資料
     */
    private void readPortData(DataLinkParserUtil parserUtil)
    {
        if (!Device.isConnect)
        {
            return;
        }
        try
        {
            if (serialPort == null)
            {
                System.out.println("Serial-序列槽對象為空,監聽失敗!");
                init();
                return;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            init();
            return;
        }
        byte[] readBuffer = new byte[4096];
        try
        {
            parserUtil.unpackData(inputStream.read(readBuffer), readBuffer);
        }
        catch (IOException ignored)
        {
            System.out.println("inputStream.read(readBuffer):ERROR!");
            init();
        }
    }

    /**
     * 給序列槽添加監聽器
     */
    private void addListener()
    {
        try
        {
            inputStream = serialPort.getInputStream();
            outputStream = serialPort.getOutputStream();
            Device.isConnect = true;
            final DataLinkParserUtil parserUtil = new DataLinkParserUtil();
            serialPort.addEventListener(new SerialPortListener(() -> readPortData(parserUtil)));
            // 設定當有資料到達時喚醒監聽接收線程
            serialPort.notifyOnDataAvailable(true);
            // 設定當通信中斷時喚醒中斷線程
            serialPort.notifyOnBreakInterrupt(true);
            new Thread(this::sendPortData).start();//發送序列槽資料
            new Thread(this::getSn).start();//發送擷取飛控編号請求
        }
        catch (TooManyListenersException | IOException e)
        {
            e.printStackTrace();
            Device.isConnect = false;
            init();
        }
    }

    /**
     * 發送序列槽資料
     */
    private void sendPortData()
    {
        while (Device.isConnect && outputStream != null)
        {
            if (Device.sendCommandQueue.isEmpty())
            {
                continue;
            }
            Packet packet = null;
            try
            {
                packet = Device.sendCommandQueue.take();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            if (packet == null)
            {
                continue;
            }
            try
            {
                outputStream.write(packet.encodePacket());
                outputStream.flush();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * 打開序列槽
     */
    private boolean openPort()
    {
        closePort();
        try
        {
            if (Parameter.isLinux)
            { //RXTX隻支援ttyS開頭的裝置,而我們要跟序列槽通訊用的是 ttyAMA0,是以在此之前還要做一下映射
                Util.exeShellCommand("sudo ln -s /dev/ttyAMA0 /dev/ttyS4502");
            }
            System.out.println("打開序列槽:PORT=" + Parameter.PORT + ",RATE=" + Parameter.RATE);
            serialPort = openPort(Parameter.PORT, Parameter.RATE);
            if (serialPort != null)
            {
                System.out.println("Serial-序列槽已打開!");
                return true;
            }
        }
        catch (PortInUseException e)
        {
            System.out.println("Serial-序列槽已被占用!");
            e.printStackTrace();
            return false;
        }
        return false;
    }

    /**
     * 打開序列槽
     *
     * @param portName 端口名稱
     * @param rate     波特率
     * @return 序列槽對象
     * @throws PortInUseException 序列槽已被占用
     */
    private SerialPort openPort(String portName, int rate) throws PortInUseException
    {
        try
        {
            // 通過端口名識别端口
            CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
            // 打開端口,并給端口名字和一個timeout(打開操作的逾時時間)
            CommPort commPort = portIdentifier.open(portName, 2000);
            // 判斷是不是序列槽
            if (!(commPort instanceof SerialPort))
            {
                System.out.println("Serial-" + portName + "不是序列槽");
                return null;
            }
            SerialPort serialPort = (SerialPort) commPort;
            try
            {
                // 設定一下序列槽的波特率等參數
                // 資料位:8
                // 停止位:1
                // 校驗位:None
                serialPort.setSerialPortParams(rate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                return serialPort;
            }
            catch (UnsupportedCommOperationException e)
            {
                e.printStackTrace();
                return null;
            }
        }
        catch (NoSuchPortException e1)
        {
            e1.printStackTrace();
            System.out.println("Serial-沒有這個端口");
            return null;
        }
    }

    /**
     * 關閉序列槽
     */
    public void closePort()
    {
        System.out.println("Serial-關閉序列槽中...");
        Device.isConnect = false;
        if (serialPort != null)
        {
            serialPort.removeEventListener();
            serialPort.close();
            serialPort = null;
        }
        if (inputStream != null)
        {
            try
            {
                inputStream.close();
                inputStream = null;
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        if (outputStream != null)
        {
            try
            {
                outputStream.close();
                outputStream = null;
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        System.out.println("Serial-序列槽已關閉");
    }
}