package robotinterface.robot.connection; import gnu.io.CommPortIdentifier; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import java.awt.EventQueue; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.LinkedList; import java.util.Queue; import javax.swing.JOptionPane; import robotinterface.util.observable.Observer; public class Serial2 implements Connection, SerialPortEventListener { private static boolean FAIL_LOAD_LIBRARY = false; private ArrayList<Observer<ByteBuffer, Connection>> observers; private SerialPort serialPort; private String defaultPort = null; private boolean isConnected = false; private int sentPackages = 0; private int receivedPackages = 0; private static final String PORT_NAMES[] = { "/dev/tty.usbserial-A9007UX1", // Mac OS X "/dev/ttyUSB#", // Linux "/dev/ttyACM#", // Linux USB 3.0 "COM#", // Windows }; /** * Input and output streams */ private InputStream input; private OutputStream output; /* * Read buffers */ private byte buffer[] = new byte[128]; private int bufferIndex; private int bufferLast; private int bufferSize = 1; // how big before reset or event firing private boolean newMessage = true; private Queue<byte[]> messages; /** * Default bits per second for COM port. */ private int dataRate = 9600; /** * Milliseconds to block while waiting for port open */ private static final int TIME_OUT = 2000; private static final int PORT_SEARCH = 10; public Serial2(int dataRate) { observers = new ArrayList<>(); this.dataRate = dataRate; messages = new LinkedList<byte[]>(); } public int getSendedPackages() { return sentPackages; } public int getReceivedPackages() { return receivedPackages; } public String getDefaultPort() { return defaultPort; } public void setDefaultPort(String defaultPort) { this.defaultPort = defaultPort; } public boolean tryConnect(String port) { CommPortIdentifier portId = null; Enumeration portEnum = null; try { portEnum = CommPortIdentifier.getPortIdentifiers(); } catch (Throwable t) { // t.printStackTrace(); throw new Error(); } if (portEnum == null) { return false; } //First, Find an instance of serial port as set in PORT_NAMES. while (portEnum.hasMoreElements()) { CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement(); if (currPortId.getName().equals(port)) { portId = currPortId; break; } } if (portId == null) { //Could not find COM port return false; } try { // open serial port, and use class name for the appName. serialPort = (SerialPort) portId.open(this.getClass().getName(), TIME_OUT); // set port parameters serialPort.setSerialPortParams(dataRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); //teste web: http://www.devmedia.com.br/utilizando-a-api-rxtx-para-manipulacao-da-serial-parte-iii/7171 serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); // open the streams input = serialPort.getInputStream(); output = serialPort.getOutputStream(); // add event listeners serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); } catch (PortInUseException e) { //porta ocupada return false; } catch (Exception e) { return false; } return true; } public Collection<String> getAvailableDevices() { ArrayList<String> avaliableDevices = new ArrayList<>(); if (FAIL_LOAD_LIBRARY) { return avaliableDevices; } for (String name : PORT_NAMES) { if (name.contains("#")) { for (int i = 0; i < PORT_SEARCH; i++) { String device = name.replace("#", "" + i); //adiciona portas ocultas e bloqueadas (Linux) System.setProperty("gnu.io.rxtx.SerialPorts", device); try { if (tryConnect(device)) { avaliableDevices.add(device); closeConnection(); } } catch (Throwable t) { EventQueue.invokeLater(new Runnable() { @Override public void run() { JOptionPane.showMessageDialog(null, "Falha ao carregar a biblioteca da porta serial.\nApenas simulação virtual disponivel.", "Erro", JOptionPane.ERROR_MESSAGE); } }); FAIL_LOAD_LIBRARY = true; return avaliableDevices; } } } } return avaliableDevices; } @Override public boolean establishConnection() { isConnected = false; // Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { // @Override // public void run() { // closeConnection(); // } // })); if (defaultPort == null) { for (String name : PORT_NAMES) { if (name.contains("#")) { for (int i = 0; i < PORT_SEARCH; i++) { String device = name.replace("#", "" + i); //adiciona portas ocultas e bloqueadas (Linux) System.setProperty("gnu.io.rxtx.SerialPorts", device); isConnected = tryConnect(device); if (isConnected) { System.out.println(device); try { Thread.sleep(1000); //espera 1s para a conexão funcionar } catch (InterruptedException ex) { } return true; } } } } } else { //adiciona portas ocultas e bloqueadas (Linux) System.setProperty("gnu.io.rxtx.SerialPorts", defaultPort); isConnected = tryConnect(defaultPort); if (isConnected) { try { Thread.sleep(1000); //espera 1s para a conexão funcionar } catch (InterruptedException ex) { } return true; } } return false; } @Override public void closeConnection() { if (serialPort != null) { serialPort.removeEventListener(); serialPort.close(); } } @Override public boolean isConnected() { return isConnected; } @Override public void attach(Observer<ByteBuffer, Connection> observer) { observers.add(observer); } @Override public void detach(Observer<ByteBuffer, Connection> observer) { observers.remove(observer); } /* * This is a modified version of serialEvent from PSerial library, * from Processing project - http://processing.org */ @Override synchronized public void serialEvent(SerialPortEvent serialEvent) { if (serialEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { /* Se a funcao retornar antes de ler toda a mensagem, o evento so sera * disparado apos 20ms. */ while ((bufferLast - bufferIndex) < bufferSize) {//input.available() > 0) { synchronized (buffer) { if (bufferLast == buffer.length) { byte temp[] = new byte[bufferLast << 1]; System.arraycopy(buffer, 0, temp, 0, bufferLast); buffer = temp; } if (input.available() > 0) { buffer[bufferLast++] = (byte) input.read(); } if ((bufferLast - bufferIndex) >= bufferSize) { if (messageHandler()) { break; } } } } } catch (IOException e) { System.out.println("serialEvent: " + e.getMessage()); } } } public boolean messageHandler() { if (newMessage) { bufferSize = read() + 2; // TODO: REMOVER + 2 newMessage = false; //System.out.println("\t1: " + System.currentTimeMillis()); } //System.out.println("Available: " + (bufferLast - bufferIndex)); if ((bufferLast - bufferIndex) >= bufferSize) { if (!observers.isEmpty()) { ByteBuffer message = ByteBuffer.allocate(bufferSize + 1); // TODO: REMOVER +1 message.put((byte) bufferSize); // TODO: REMOVER readBytes(message); message.flip(); for (Observer<ByteBuffer, Connection> o : observers) { o.update(message.asReadOnlyBuffer(), this); } } else { byte[] message = new byte[bufferSize]; readBytes(message); synchronized (messages) { messages.add(message); } } receivedPackages++; newMessage = true; bufferSize = 1; return true; //System.out.println("\t2: " + System.currentTimeMillis()); } return false; } @Override public void send(byte[] data) { try { sentPackages++; output.write(data.length); output.write(data); output.flush(); } catch (IOException ex) { System.out.println("Send fail!"); } } @Override public void send(ByteBuffer data) { int length = data.remaining(); byte[] msg = new byte[length]; data.get(msg); send(msg); } public void buffer(int count) { bufferSize = count; } @Override public boolean available() { return (!messages.isEmpty()); } public void clear() { bufferLast = 0; bufferIndex = 0; } @Override public int receive(byte[] b, int size) { synchronized (messages) { if (!messages.isEmpty()) { byte[] lastMessage = messages.poll(); int length = lastMessage.length; if (length > size) { length = size; } System.arraycopy(lastMessage, 0, b, 0, length); return length; } else { return 0; } } } public int read() { if (bufferIndex == bufferLast) { return -1; } synchronized (buffer) { int outgoing = buffer[bufferIndex++] & 0xff; if (bufferIndex == bufferLast) { // rewind bufferIndex = 0; bufferLast = 0; } return outgoing; } } public byte[] readBytes() { if (bufferIndex == bufferLast) { return null; } synchronized (buffer) { int length = bufferLast - bufferIndex; byte outgoing[] = new byte[length]; System.arraycopy(buffer, bufferIndex, outgoing, 0, length); bufferIndex = 0; // rewind bufferLast = 0; return outgoing; } } public int readBytes(byte outgoing[]) { if (bufferIndex == bufferLast) { return 0; } synchronized (buffer) { int length = bufferLast - bufferIndex; if (length > outgoing.length) { length = outgoing.length; } System.arraycopy(buffer, bufferIndex, outgoing, 0, length); bufferIndex += length; if (bufferIndex == bufferLast) { bufferIndex = 0; // rewind bufferLast = 0; } return length; } } public int readBytes(ByteBuffer outgoing) { if (bufferIndex == bufferLast) { return 0; } synchronized (buffer) { int length = bufferLast - bufferIndex; if (length > outgoing.capacity()) { length = outgoing.capacity(); } outgoing.put(buffer, bufferIndex, length); bufferIndex += length; if (bufferIndex == bufferLast) { bufferIndex = 0; // rewind bufferLast = 0; } return length; } } public static void printBytes(String str) { byte[] array = str.getBytes(); printBytes(array, array.length); } public static void printBytes(byte[] array, int size) { //System.out.print("Received: "); System.out.print("[" + size + "]{"); for (int i = 0; i < size; i++) { System.out.print("," + (int) (array[i] & 0xff)); } System.out.println("}"); } public static void main(String[] args) { Serial2 s = new Serial2(57600); ArrayList<byte[]> testMessages = new ArrayList<>(); /* TESTE DO RÁDIO */ //ATENÇÃO: trocar intervalo de tempo na linha ~435 //coloca 100 mensagens na lista de espera int numMessages = 100; for (int i = 0; i < numMessages; i++) { testMessages.add(new byte[]{1, 2, 3, 4, 5}); } if (s.establishConnection()) { System.out.println("connected\n"); int sended = 0; int failed = 0; byte[] buffer = new byte[20]; long timeSum = 0; for (int i = 0; i < 1; i++) { //repetição for (byte[] message : testMessages) { boolean timeout = false; long timestamp = System.currentTimeMillis(); sended++; s.send(message); System.out.print("Sended [" + sended + "]: "); printBytes(message, message.length); while (!s.available()) { try { Thread.sleep(1); //tempo maximo para enviar: ~20ms da RXTXcomm + 8ms do radio if ((System.currentTimeMillis() - timestamp) >= 1000) { numMessages--; timeout = true; break; } } catch (InterruptedException ex) { } } if (!timeout) { int lenght = s.receive(buffer, buffer.length); if (buffer[0] != 11) { System.out.print("Received [" + sended + "]: "); printBytes(buffer, lenght); long rtt = System.currentTimeMillis() - timestamp; timeSum += rtt; System.out.println(" @Time [" + sended + "]: " + rtt + "ms\n"); } else { failed++; System.out.println("Failed\n"); } } else { failed++; System.out.println("Timeout\n"); } try { Thread.sleep(10); } catch (InterruptedException ex) { } } System.out.println("Average Time: " + timeSum / numMessages + "ms\n"); System.out.println("Sended: " + sended + "\tFailed: " + failed); try { Thread.sleep(1000); } catch (InterruptedException ex) { } } } else { System.out.println("fail"); } System.out.println("Fim"); System.exit(0); } }