/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2009-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) 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. * * OpenNMS(R) 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 OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.rxtx.test.internal; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.RXTXVersion; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.TooManyListenersException; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; import org.ops4j.io.*; /** * Internal implementation of our example OSGi service * * @author ranger * @version $Id: $ */ public final class RxtxCommands implements CommandProvider { private final class EventLogger implements SerialPortEventListener { private final CommandInterpreter intp; private EventLogger(CommandInterpreter intp) { this.intp = intp; } public void serialEvent(SerialPortEvent ev) { switch( ev.getEventType() ) { case SerialPortEvent.BI: intp.println(String.format("EVENT: Received BI event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.CD: intp.println(String.format("EVENT: Received CD event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.CTS: intp.println(String.format("EVENT: Received CTS event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.DATA_AVAILABLE: intp.println(String.format("EVENT: Received DATA_AVAIL event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.DSR: intp.println(String.format("EVENT: Received DSR event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.FE: intp.println(String.format("EVENT: Received FE event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.OE: intp.println(String.format("EVENT: Received OE event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.OUTPUT_BUFFER_EMPTY: intp.println(String.format("EVENT: Received OUT_BUF_EMPTY event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.PE: intp.println(String.format("EVENT: Received PE event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; case SerialPortEvent.RI: intp.println(String.format("EVENT: Received RI event: changed %s to %s", ev.getOldValue(), ev.getNewValue())); break; } } } private Map<String, SerialPort> m_openPorts = new HashMap<String, SerialPort>(); private Map<String, Pipe> m_loggingPorts = new HashMap<String, Pipe>(); /** * <p>_rxtxVersion</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxVersion(CommandInterpreter intp) { intp.println( "RXTX Version: " + RXTXVersion.getVersion() ); intp.println( "RXTX NativeVersion: " + RXTXVersion.nativeGetVersion() ); return null; } /** * <p>_rxtxListPorts</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxListPorts(CommandInterpreter intp) { Enumeration<?> en = CommPortIdentifier.getPortIdentifiers(); while( en.hasMoreElements() ) { CommPortIdentifier commPortId = (CommPortIdentifier) en.nextElement(); intp.println( "Port: " + commPortId.getName() + " Type: " + commPortId.getPortType() ); } return null; } /** * <p>_rxtxOpen</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxOpen(CommandInterpreter intp) { String id = intp.nextArgument(); String port = intp.nextArgument(); if( id == null || port == null ) { intp.println("usage: rxtxOpen <id> <port>"); return null; } if ( m_openPorts.containsKey( id ) ) { intp.println("there is already a port with id " + id ); return null; } CommPortIdentifier portId; try { portId = CommPortIdentifier.getPortIdentifier(port); if ( portId.getPortType() != CommPortIdentifier.PORT_SERIAL ) { intp.println( "Only Serial Ports are currently supported." ); return null; } } catch ( NoSuchPortException e ) { intp.println( "port not found: " + e.getMessage() ); return null; } try { SerialPort commPort = (SerialPort)portId.open("rxtx-test", 4000); m_openPorts.put( id, commPort ); intp.println( "Port " + commPort.getName() + " assigned to id " + id ); return null; } catch (PortInUseException e) { intp.println( "exception opening port: " + e.getMessage() ); return null; } } /** * <p>_rxtxClose</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxClose(CommandInterpreter intp) { try { String id = intp.nextArgument(); assertNotNull( id , "usage: rxtxClose <id>"); assertOpenPort( id ); Pipe pipe = m_loggingPorts.remove( id ); if( pipe != null ) { pipe.stop(); } SerialPort port = m_openPorts.remove( id ); intp.print("Closing port " + port.getName() + " with id " + id + "..." ); port.close(); intp.println("done."); } catch( IllegalArgumentException e) { intp.println( e.getMessage() ); } return null; } /** * <p>_rxtxWrite</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxWrite(CommandInterpreter intp) { String id = intp.nextArgument(); String text = intp.nextArgument(); try { assertNotNull( id , "usage: rxtxWrite <id> <text>" ); assertNotNull( text , "usage: rxtxWrite <id> <text>" ); assertOpenPort( id ); SerialPort port = m_openPorts.get( id ); Writer out = new OutputStreamWriter( port.getOutputStream(), "US-ASCII" ); if ( text.startsWith( "<<" ) ) { String eof = text.substring( 2 ); BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) ); String line = in.readLine(); while( ! eof.equals( line ) ) { out.write( line + "\r\n"); out.flush(); line = in.readLine(); } } else { text = text.replace("\\r", "\r"); text = text.replace("\\n", "\n"); text = text.replace("\\\\", "\\"); out.write( text + "\r\n"); out.flush(); } } catch( IllegalArgumentException e ) { intp.println( e.getMessage() ); } catch( UnsupportedEncodingException e ) { intp.println( "Unsupported Encoded " + e.getMessage() ); } catch( IOException e ) { intp.println( "Exception writing " + text + " to port with id " + id ); intp.printStackTrace( e ); } return null; } /** * <p>_rxtxRead</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxRead(CommandInterpreter intp) { try { String id = intp.nextArgument(); assertNotNull( id, "usage: rxtxRead <id> <timeout>" ); assertOpenPort( id ); SerialPort port = m_openPorts.get( id ); Reader r = new InputStreamReader(port.getInputStream(), "US-ASCII"); while( r.ready() ) { intp.print( (char)r.read() ); } } catch( IllegalArgumentException e) { intp.println( e.getMessage() ); } catch( Exception e) { intp.println( "Exception will reading."); intp.printStackTrace( e ); } return null; } /** * <p>_rxtxLog</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxLog(CommandInterpreter intp) { try { String id = intp.nextArgument(); assertNotNull( id, "usage: rxtxLog <id>"); assertOpenPort( id ); SerialPort port = m_openPorts.get( id ); Pipe pipe = new Pipe( port.getInputStream(), System.out ).start( "Modem DataStream" ); m_loggingPorts.put( id, pipe ); } catch( IllegalArgumentException e) { intp.println( e.getMessage() ); } catch( IOException e) { intp.println( "Error reading from port"); intp.printStackTrace( e ); } return null; } /** * <p>_rxtxUnlog</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxUnlog(CommandInterpreter intp) { try { String id = intp.nextArgument(); assertNotNull(id, "usage: rxtxUnlog <id>"); assertOpenPort( id ); assertTrue( m_loggingPorts.containsKey( id ), "port with id "+ id +" is not currently logging"); Pipe pipe = m_loggingPorts.remove( id ); pipe.stop(); } catch(IllegalArgumentException e) { intp.println(e.getMessage()); } return null; } /** * <p>_rxtxInfo</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. * @return a {@link java.lang.Object} object. */ public Object _rxtxInfo(CommandInterpreter intp) { try { String id = intp.nextArgument(); assertNotNull( id, "usage: rxtxInfo <id>" ); assertOpenPort( id ); SerialPort port = m_openPorts.get( id ); intp.println("===== Info for port " + port.getName() + " ====="); // Unsupported by ACM driver //intp.println("\tbaudBase: " + port.getBaudBase() ); intp.println("\tbaudRate: " + port.getBaudRate() ); // Unsupported by RXTX //intp.println("\tcallOutHangup: " + port.getCallOutHangup() ); intp.println("\tisCD: " + port.isCD() ); intp.println("\tisCTS: " + port.isCTS() ); intp.println("\tisDSR: " + port.isDSR() ); intp.println("\tisDTR: " + port.isDTR() ); intp.println("\tisRI: " + port.isRI() ); intp.println("\tisRTS: " + port.isRTS() ); intp.println("\tdataBits: " + port.getDataBits() ); // Unsupported by ACM driver //intp.println("\tdivisor: " + port.getDivisor() ); intp.println("\tendOfInputChar: " + port.getEndOfInputChar() ); intp.println("\tflowControlMode: " + port.getFlowControlMode() ); intp.println("\tinputBufferSize: " + port.getInputBufferSize() ); // Unsupported by RXTX //intp.println("\tlowLatency: " + port.getLowLatency() ); intp.println("\toutputBufferSize: " + port.getOutputBufferSize() ); intp.println("\tparity: " + port.getParity() ); intp.println("\tparityErrorChar: " + port.getParityErrorChar() ); intp.println("\treceiveFramingEnabled: " + port.isReceiveFramingEnabled() ); intp.println("\treceiveFramingByte: " + port.getReceiveFramingByte() ); intp.println("\treceiveThresholdEnabled: " + port.isReceiveThresholdEnabled() ); intp.println("\treceiveThreshold: " + port.getReceiveThreshold() ); intp.println("\treceiveTimeoutEnabled: " + port.isReceiveTimeoutEnabled() ); intp.println("\treceiveTimeout: " + port.getReceiveTimeout() ); intp.println("\tstopBits: " + port.getStopBits() ); // Unsupported by RXTX //intp.println("\tuartType: " + port.getUARTType() ); intp.println("==================================================="); } catch( IllegalArgumentException e) { intp.println( e.getMessage() ); } catch( Exception e ) { intp.printStackTrace(e); } return null; } /** * <p>_rxtxEnableEvents</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. */ public void _rxtxEnableEvents(final CommandInterpreter intp) { try { String id = intp.nextArgument(); assertNotNull( id, "usage: rxtxEnableEvents <id>" ); assertOpenPort( id ); SerialPort port = m_openPorts.get( id ); SerialPortEventListener listener = new EventLogger(intp); port.addEventListener(listener); port.notifyOnBreakInterrupt(true); port.notifyOnCarrierDetect(true); port.notifyOnCTS(true); port.notifyOnDataAvailable(true); port.notifyOnDSR(true); port.notifyOnFramingError(true); port.notifyOnOutputEmpty(true); port.notifyOnOverrunError(true); port.notifyOnParityError(true); port.notifyOnRingIndicator(true); } catch( TooManyListenersException e ) { intp.printStackTrace(e); } catch( IllegalArgumentException e ) { intp.println( e.getMessage() ); } } /** * <p>_rxtxDisableEvents</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. */ public void _rxtxDisableEvents(CommandInterpreter intp) { try { String id = intp.nextArgument(); assertNotNull( id, "usage: rxtxDisableEvents <id>" ); assertOpenPort( id ); SerialPort port = m_openPorts.get( id ); removeListener( port ); } catch( IllegalArgumentException e) { intp.print( e.getMessage() ); } } private void removeListener(SerialPort port) { port.notifyOnRingIndicator( false ); port.notifyOnParityError( false ); port.notifyOnOverrunError( false ); port.notifyOnOutputEmpty( false ); port.notifyOnFramingError( false ); port.notifyOnDSR( false ); port.notifyOnDataAvailable( false ); port.notifyOnCTS( false ); port.notifyOnCarrierDetect( false ); port.notifyOnBreakInterrupt( false ); port.removeEventListener(); } /** * <p>_rxtxEventTest</p> * * @param intp a {@link org.eclipse.osgi.framework.console.CommandInterpreter} object. */ public void _rxtxEventTest(CommandInterpreter intp) { try { String port = intp.nextArgument(); String testString = intp.nextArgument(); assertNotNull( port , "usage: rxtxEventTest <port>" ); String[] args = testString == null ? new String[] { port } : new String[] { port, testString }; LoopbackEventTest.SerialEventHandler.main( args ); } catch( IllegalArgumentException e ) { intp.println( e.getMessage() ); } } /** * <p>getHelp</p> * * @return a {@link java.lang.String} object. */ public String getHelp() { StringBuilder buf = new StringBuilder(); buf.append("--- RXTX Commands ---") .append("\n\t").append("rxtxVersion -- display the rxtx version") .append("\n\t").append("rxtxListPorts -- list the available ports") .append("\n\t").append("rxtxOpen <id> <port> -- open <port> and assign to <id>") .append("\n\t").append("rxtxClose <id> -- close port <id>") .append("\n\t").append("rxtxInfo <id> -- print info about port <id>") .append("\n\t").append("rxtxRead <id> -- read all available bytes from port <id>") .append("\n\t").append("rxtxWrite <id> <text> -- write <text> to port <id> followed by \\r\\n") .append("\n\t").append("rxtxLog <id> -- redirect all bytes from port <id> to stdin") .append("\n\t").append("rxtxUnlog <id> -- stop redirectory of data from port <id>") .append("\n\t").append("rxtxEnableEvents <id> -- enable logging of events for port <id>") .append("\n\t").append("rxtxDisableEvents <id> -- disable logging of events for port <id>") .append("\n\t").append("rxtxEventTest <port> -- test serial events on device") .append("\n"); return buf.toString(); } /** * <p>stop</p> */ public void stop() { for( Pipe pipe : m_loggingPorts.values() ) { pipe.stop(); } m_loggingPorts.clear(); System.out.print( "Closing " + m_openPorts.size() + " open comm ports... "); for( SerialPort port : m_openPorts.values() ) { removeListener( port ); port.close(); } m_openPorts.clear(); System.out.println("done."); } private void assertNotNull(Object arg, String msg) { assertFalse( arg == null, msg ); } private void assertOpenPort(String id) { assertTrue( m_openPorts.containsKey( id ), "No open port with id " + id + " found."); } private void assertTrue(boolean test, String msg) { if( !test ) { throw new IllegalArgumentException( msg ); } } private void assertFalse(boolean test, String msg) { if( test ) { throw new IllegalArgumentException( msg ); } } }