/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. 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.cirqwizard.serial; import jssc.SerialPort; import jssc.SerialPortException; import jssc.SerialPortTimeoutException; import org.cirqwizard.logging.LoggerFactory; import java.io.*; public class SerialInterfaceImpl implements SerialInterface { private SerialPort port; private int baudrate; private String portName; private int timeout = -1; public SerialInterfaceImpl(String commPortName, int baudrate) throws SerialException { this.baudrate = baudrate; try { initUSART(commPortName, baudrate, SerialPort.PARITY_NONE); } catch (SerialPortException e) { throw new SerialException(e); } } private void initUSART(String name, int baudrate, int parity) throws SerialPortException { if (port != null) port.closePort(); portName = name; port = new SerialPort(portName); port.openPort(); port.setParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, parity); } public void setBootloaderMode(boolean bootloader) throws SerialException { try { initUSART(portName, bootloader ? 57600 : baudrate, bootloader ? SerialPort.PARITY_EVEN : SerialPort.PARITY_NONE); timeout = bootloader ? 25000 : -1; } catch (Exception e) { LoggerFactory.logException("Could not switch to bootloader mode", e); } } public void write(int b) throws IOException { try { port.writeByte((byte) b); } catch (SerialPortException e) { throw new IOException(e); } } @Override public void write(byte[] b) throws IOException { try { port.writeBytes(b); } catch (SerialPortException e) { throw new IOException(e); } } public int readByte() throws IOException { byte[] b; try { if (timeout > 0) b = port.readBytes(1, timeout); else b = port.readBytes(1); return b[0]; } catch (SerialPortException | SerialPortTimeoutException e) { throw new IOException(e); } } public void close() throws SerialException { try { port.closePort(); } catch (SerialPortException e) { throw new SerialException(e); } } private void sendCommand(String command, long timeout, StringBuilder response, boolean suppressExceptions) throws SerialException, ExecutionException, InterruptedException { timeout += System.currentTimeMillis(); try { port.readBytes(); port.writeString(command); port.writeString("\n"); LoggerFactory.getSerialLogger().fine(command + "\n"); StringBuffer buffer = new StringBuffer(); while (System.currentTimeMillis() < timeout) { String s = port.readString(); if (s == null) { Thread.sleep(10); continue; } buffer.append(s); String str = buffer.toString(); if (str.indexOf('\n') >= 0) { if (response != null) response.append(str); LoggerFactory.getSerialLogger().fine(str); if (str.startsWith("ok")) return; if (str.startsWith("nack") && !suppressExceptions) throw new SerialException("Negative acknowledgement received: " + str); if (str.startsWith("error") && !suppressExceptions) throw new ExecutionException("Execution error received from controller: " + str); if (!suppressExceptions) throw new SerialException("Unexpected confirmation received from controller: " + str); return; } } } catch (SerialPortException e) { throw new SerialException(e); } throw new SerialException("Timeout."); } public void send(String str, long timeout) throws SerialException, ExecutionException, InterruptedException { send(str, timeout, null, false); } public void send(String str, long timeout, StringBuilder response, boolean suppressExceptions) throws SerialException, ExecutionException, InterruptedException { try { LineNumberReader reader = new LineNumberReader(new StringReader(str)); String line; while ((line = reader.readLine()) != null) { try { sendCommand(line, timeout, response, suppressExceptions); } catch (SerialException e) { LoggerFactory.logException("Communication error detected, resending command", e); sendCommand(line, timeout, response, suppressExceptions); } } } catch (IOException e) { // It's not going to happen LoggerFactory.logException("Improbable exception", e); } } public String getPortName() { return portName; } }