/* openaltimeter -- an open-source altimeter for RC aircraft Copyright (C) 2010-2011 Jony Hudson, Jan Steidl http://openaltimeter.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.openaltimeter.comms; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import gnu.io.UnsupportedCommOperationException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.Enumeration; import java.util.List; import java.util.TooManyListenersException; import java.util.Vector; import org.openaltimeter.desktopapp.Controller; public class SerialLink { private SerialPort sp; public InputStream in; private OutputStream out; public static List<String> getSerialPorts() { @SuppressWarnings("unchecked") Enumeration<CommPortIdentifier> commPorts = CommPortIdentifier.getPortIdentifiers(); List<String> commPortNames = new Vector<String>(); while (commPorts.hasMoreElements()) commPortNames.add(commPorts.nextElement().getName()); return commPortNames; } public void connect(String port, int rate) throws NoSuchPortException, PortInUseException, UnsupportedCommOperationException, IOException, TooManyListenersException { CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(port); sp = (SerialPort) portID.open("openaltimeter comm port", rate); sp.setSerialPortParams(rate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); sp.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); // hook up to the SerialEvents - we don't activate this event listener unless we're doing a buffered read sp.addEventListener(new SerialPortEventListener() { @Override public void serialEvent(SerialPortEvent arg0) { try { while (in.available() > 0) buffer[bufferPos++] = (byte)in.read(); } catch (IOException e) { // we can't throw this exception, so the best we can do is log it and carry on. Controller.log("Error reading serial stream. Try downloading again.", "error"); } } }); // sp.setInputBufferSize(Altimeter.FLASH_MEMORY_SIZE + 1024); in = sp.getInputStream(); out = sp.getOutputStream(); } public void disconnect() { sp.close(); } public void sendReset() { sp.setDTR(false); // we're resetting the board, so it makes sense to clear any junk out of // the input buffer here. clearInput(); try {Thread.sleep(100);} catch (InterruptedException e) {} sp.setDTR(true); } // we'll often want to remove junk from the input buffer before exchanging // data with the logger. This method does just that. public void clearInput() { try { in.skip(in.available()); } catch (IOException e) {} } public void write(char c) throws IOException { out.write(c); } public void write(String s) throws IOException { char[] chars = s.toCharArray(); for (char c : chars) out.write(c); } public String readString(int bufferSize) throws IOException { byte[] inputBuffer = new byte[bufferSize]; in.read(inputBuffer, 0, bufferSize); return new String(inputBuffer, Charset.forName("ASCII")).trim(); } private byte[] buffer; private int bufferPos; // this method and the following three implement a very simple buffered read. // It shouldn't be necessary to do this, as java has buffered streams, but I // simply couldn't get them to work well with rxtx. public void startBufferedRead(int bufferSize) { buffer = new byte[bufferSize]; bufferPos = 0; sp.notifyOnDataAvailable(true); } public void stopBufferedRead() { sp.notifyOnDataAvailable(false); } public int available() { return bufferPos; } public byte[] getBuffer() { return buffer; } }