Java tutorial
/** * Copyright (c) 2010-2018 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.irtrans.handler; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.NoConnectionPendingException; import java.nio.channels.NotYetConnectedException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.smarthome.config.core.Configuration; import org.eclipse.smarthome.core.library.types.StringType; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.Channel; import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.ThingStatus; import org.eclipse.smarthome.core.thing.ThingStatusDetail; import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler; import org.eclipse.smarthome.core.types.Command; import org.eclipse.smarthome.core.types.RefreshType; import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.irtrans.IRtransBindingConstants; import org.openhab.binding.irtrans.IRtransBindingConstants.Led; import org.openhab.binding.irtrans.IrCommand; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The {@link EthernetBridgeHandler} is responsible for handling commands, which * are sent to one of the channels. * * @author Karel Goderis - Initial contribution * @since 2.3.0 * */ public class EthernetBridgeHandler extends BaseBridgeHandler implements TransceiverStatusListener { // List of Configuration constants public static final String BUFFER_SIZE = "bufferSize"; public static final String IP_ADDRESS = "ipAddress"; public static final String IS_LISTENER = "isListener"; public static final String FIRMWARE_VERSION = "firmwareVersion"; public static final String LISTENER_PORT = "listenerPort"; public static final String MODE = "mode"; public static final String PING_TIME_OUT = "pingTimeOut"; public static final String PORT_NUMBER = "portNumber"; public static final String RECONNECT_INTERVAL = "reconnectInterval"; public static final String REFRESH_INTERVAL = "refreshInterval"; public static final String RESPONSE_TIME_OUT = "responseTimeOut"; public static final String COMMAND = "command"; public static final String LED = "led"; public static final String REMOTE = "remote"; public static final int LISTENING_INTERVAL = 100; private static final Pattern RESPONSE_PATTERN = Pattern.compile("..(\\d{5}) (.*)", Pattern.DOTALL); private static final Pattern HEX_PATTERN = Pattern.compile("RCV_HEX (.*)"); private static final Pattern IRDB_PATTERN = Pattern.compile("RCV_COM (.*),(.*),(.*),(.*)"); private Logger logger = LoggerFactory.getLogger(EthernetBridgeHandler.class); private Selector selector; private Thread pollingThread; private SocketChannel socketChannel; protected SelectionKey socketChannelKey; protected ServerSocketChannel listenerChannel; protected SelectionKey listenerKey; protected boolean previousConnectionState; private final Lock lock = new ReentrantLock(); private List<TransceiverStatusListener> transceiverStatusListeners = new CopyOnWriteArrayList<>(); /** * Data structure to store the infrared commands that are 'loaded' from the * configuration files. Command loading from pre-defined configuration files is not supported * (anymore), but the code is maintained in case this functionality is re-added in the future **/ protected final Collection<IrCommand> irCommands = new HashSet<IrCommand>(); public EthernetBridgeHandler(Bridge bridge) { super(bridge); // Nothing to do here } @Override public void initialize() { // register ourselves as a Transceiver Status Listener registerTransceiverStatusListener(this); try { selector = Selector.open(); } catch (IOException e) { logger.debug("An exception occurred while registering the selector: '{}'", e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, e.getMessage()); } if (selector != null) { if (getConfig().get(IP_ADDRESS) != null && getConfig().get(PORT_NUMBER) != null) { if (pollingThread == null) { pollingThread = new Thread(pollingRunnable, "ESH-IRtrans-Polling " + getThing().getUID()); pollingThread.start(); } } else { logger.debug("Cannot connect to IRtrans Ethernet device. IP address or port number not set."); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "IP address or port number not set."); } if (getConfig().get(IS_LISTENER) != null) { configureListener((String) getConfig().get(LISTENER_PORT)); } } } @Override public void dispose() { unregisterTransceiverStatusListener(this); try { if (socketChannel != null) { socketChannel.close(); } } catch (IOException e) { logger.warn("An exception occurred while closing the channel '{}': {}", socketChannel, e.getMessage()); } try { if (listenerChannel != null) { listenerChannel.close(); } } catch (IOException e) { logger.warn("An exception occurred while closing the channel '{}': {}", listenerChannel, e.getMessage()); } try { if (selector != null) { selector.close(); } } catch (IOException e) { logger.debug("An exception occurred while closing the selector: '{}'", e.getMessage()); } logger.debug("Stopping the IRtrans polling Thread for {}", getThing().getUID()); if (pollingThread != null) { pollingThread.interrupt(); try { pollingThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } pollingThread = null; } } public boolean registerTransceiverStatusListener(@NonNull TransceiverStatusListener transceiverStatusListener) { return transceiverStatusListeners.add(transceiverStatusListener); } public boolean unregisterTransceiverStatusListener( @NonNull TransceiverStatusListener transceiverStatusListener) { return transceiverStatusListeners.remove(transceiverStatusListener); } public void onConnectionLost() { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); try { if (socketChannel != null) { socketChannel.close(); } } catch (IOException e) { logger.warn("An exception occurred while closing the channel '{}': {}", socketChannel, e.getMessage()); } establishConnection(); } public void onConnectionResumed() { configureTransceiver(); updateStatus(ThingStatus.ONLINE); } private void establishConnection() { lock.lock(); try { if (getConfig().get(IP_ADDRESS) != null && getConfig().get(PORT_NUMBER) != null) { try { socketChannel = SocketChannel.open(); socketChannel.socket().setKeepAlive(true); socketChannel.configureBlocking(false); synchronized (selector) { selector.wakeup(); int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT; socketChannelKey = socketChannel.register(selector, interestSet); } InetSocketAddress remoteAddress = new InetSocketAddress((String) getConfig().get(IP_ADDRESS), ((BigDecimal) getConfig().get(PORT_NUMBER)).intValue()); socketChannel.connect(remoteAddress); } catch (IOException e) { logger.debug("An exception occurred while connecting to '{}:{}' : {}", getConfig().get(IP_ADDRESS), ((BigDecimal) getConfig().get(PORT_NUMBER)).intValue(), e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); } try { Thread.sleep(((BigDecimal) getConfig().get(RESPONSE_TIME_OUT)).intValue()); } catch (NumberFormatException | InterruptedException e) { Thread.currentThread().interrupt(); logger.debug("An exception occurred while putting a thread to sleep: '{}'", e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); } onConnectable(); } } finally { lock.unlock(); } } @Override public void onCommandReceived(EthernetBridgeHandler bridge, IrCommand command) { logger.debug("Received infrared command '{},{}' for thing '{}'", command.getRemote(), command.getCommand(), this.getThing().getUID()); for (Channel channel : getThing().getChannels()) { Configuration channelConfiguration = channel.getConfiguration(); if (channel.getAcceptedItemType() != null && channel.getAcceptedItemType().equals(IRtransBindingConstants.RECEIVER_CHANNEL_TYPE)) { IrCommand thingCompatibleCommand = new IrCommand(); thingCompatibleCommand.setRemote((String) channelConfiguration.get(REMOTE)); thingCompatibleCommand.setCommand((String) channelConfiguration.get(COMMAND)); if (command.matches(thingCompatibleCommand)) { StringType stringType = new StringType(command.getRemote() + "," + command.getCommand()); logger.debug("Received a matching infrared command '{}' for channel '{}'", stringType, channel.getUID()); updateState(channel.getUID(), stringType); } } } } @Override public void handleCommand(ChannelUID channelUID, Command command) { if (!(command instanceof RefreshType)) { Channel channel = this.getThing().getChannel(channelUID.getId()); if (channel != null) { Configuration channelConfiguration = channel.getConfiguration(); if (channel.getAcceptedItemType() != null && channel.getAcceptedItemType().equals(IRtransBindingConstants.BLASTER_CHANNEL_TYPE)) { if (command instanceof StringType) { String remoteName = StringUtils.substringBefore(command.toString(), ","); String irCommandName = StringUtils.substringAfter(command.toString(), ","); IrCommand ircommand = new IrCommand(); ircommand.setRemote(remoteName); ircommand.setCommand(irCommandName); IrCommand thingCompatibleCommand = new IrCommand(); thingCompatibleCommand.setRemote((String) channelConfiguration.get(REMOTE)); thingCompatibleCommand.setCommand((String) channelConfiguration.get(COMMAND)); if (ircommand.matches(thingCompatibleCommand)) { if (sendIRcommand(ircommand, Led.get((String) channelConfiguration.get(LED)))) { logger.debug("Sent a matching infrared command '{}' for channel '{}'", command, channelUID); } else { logger.warn( "An error occured whilst sending the infrared command '{}' for Channel '{}'", command, channelUID); } } } } if (channel.getAcceptedItemType() != null && channel.getAcceptedItemType().equals(IRtransBindingConstants.RECEIVER_CHANNEL_TYPE)) { logger.warn("Receivers can only receive infrared commands, not send them"); } } } } private void configureListener(String listenerPort) { try { listenerChannel = ServerSocketChannel.open(); listenerChannel.socket().bind(new InetSocketAddress(Integer.parseInt(listenerPort))); listenerChannel.configureBlocking(false); logger.info("Listening for incoming connections on {}", listenerChannel.getLocalAddress()); synchronized (selector) { selector.wakeup(); try { listenerKey = listenerChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (ClosedChannelException e1) { logger.debug("An exception occurred while registering a selector: '{}'", e1.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e1.getMessage()); } } } catch (IOException e3) { logger.error( "An exception occurred while creating configuring the listener channel on port number {}: '{}'", Integer.parseInt(listenerPort), e3.getMessage()); } } protected void configureTransceiver() { lock.lock(); try { String putInASCIImode = "ASCI"; ByteBuffer response = sendCommand(putInASCIImode); String getFirmwareVersion = "Aver" + (char) 13; response = sendCommand(getFirmwareVersion); if (response != null) { String message = stripByteCount(response).split("\0")[0]; if (message != null) { if (message.contains("VERSION")) { logger.info("'{}' matches an IRtrans device with firmware {}", getThing().getUID(), message); getConfig().put(FIRMWARE_VERSION, message); } else { logger.debug("Received some non-compliant garbage ({})", message); onConnectionLost(); } } } else { try { logger.debug("Did not receive an answer from the IRtrans transceiver '{}' - Parsing is skipped", socketChannel.getRemoteAddress()); onConnectionLost(); } catch (IOException e1) { logger.debug("An exception occurred while getting a remote address: '{}'", e1.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e1.getMessage()); } } int numberOfRemotes = 0; int numberOfRemotesProcessed = 0; int numberOfRemotesInBatch = 0; String[] remoteList = getRemoteList(0); if (remoteList.length > 0) { logger.debug("The IRtrans device for '{}' supports '{}' remotes", getThing().getUID(), remoteList[1]); numberOfRemotes = Integer.valueOf(remoteList[1]); numberOfRemotesInBatch = Integer.valueOf(remoteList[2]); } while (numberOfRemotesProcessed < numberOfRemotes) { for (int i = 1; i <= numberOfRemotesInBatch; i++) { String remote = remoteList[2 + i]; // get remote commands String[] commands = getRemoteCommands(remote, 0); StringBuilder result = new StringBuilder(); int numberOfCommands = 0; int numberOfCommandsInBatch = 0; int numberOfCommandsProcessed = 0; if (commands.length > 0) { numberOfCommands = Integer.valueOf(commands[1]); numberOfCommandsInBatch = Integer.valueOf(commands[2]); numberOfCommandsProcessed = 0; } while (numberOfCommandsProcessed < numberOfCommands) { for (int j = 1; j <= numberOfCommandsInBatch; j++) { String command = commands[2 + j]; result.append(command); numberOfCommandsProcessed++; if (numberOfCommandsProcessed < numberOfCommands) { result.append(", "); } } if (numberOfCommandsProcessed < numberOfCommands) { commands = getRemoteCommands(remote, numberOfCommandsProcessed); if (commands.length == 0) { break; } numberOfCommandsInBatch = Integer.valueOf(commands[2]); } else { numberOfCommandsInBatch = 0; } } logger.debug("The remote '{}' on '{}' supports '{}' commands: {}", remote, getThing().getUID(), numberOfCommands, result.toString()); numberOfRemotesProcessed++; } if (numberOfRemotesProcessed < numberOfRemotes) { remoteList = getRemoteList(numberOfRemotesProcessed); if (remoteList.length == 0) { break; } numberOfRemotesInBatch = Integer.valueOf(remoteList[2]); } else { numberOfRemotesInBatch = 0; } } } finally { lock.unlock(); } } private String[] getRemoteCommands(String remote, int index) { String getCommands = "Agetcommands " + remote + "," + index + (char) 13; ByteBuffer response = sendCommand(getCommands); String[] commandList = new String[0]; if (response != null) { String message = stripByteCount(response).split("\0")[0]; logger.trace("commands returned {}", message); if (message != null) { if (message.contains("COMMANDLIST")) { commandList = message.split(","); } else { logger.debug("Received some non-compliant command ({})", message); onConnectionLost(); } } } else { logger.debug("Did not receive an answer from the IRtrans transceiver for '{}' - Parsing is skipped", getThing().getUID()); onConnectionLost(); } return commandList; } private String[] getRemoteList(int index) { String getRemotes = "Agetremotes " + index + (char) 13; ByteBuffer response = sendCommand(getRemotes); String[] remoteList = new String[0]; if (response != null) { String message = stripByteCount(response).split("\0")[0]; logger.trace("remotes returned {}", message); if (message != null) { if (message.contains("REMOTELIST")) { remoteList = message.split(","); } else { logger.debug("Received some non-compliant command ({})", message); onConnectionLost(); } } } else { logger.debug("Did not receive an answer from the IRtrans transceiver for '{}' - Parsing is skipped", getThing().getUID()); onConnectionLost(); } return remoteList; } public boolean sendIRcommand(IrCommand command, Led led) { // construct the string we need to send to the IRtrans device String output = packIRDBCommand(led, command); lock.lock(); try { ByteBuffer response = sendCommand(output); if (response != null) { String message = stripByteCount(response).split("\0")[0]; if (message != null && message.contains("RESULT OK")) { return true; } else { logger.debug("Received an unexpected response from the IRtrans transceiver: '{}'", message); return false; } } } finally { lock.unlock(); } return false; } private ByteBuffer sendCommand(String command) { if (command != null) { ByteBuffer byteBuffer = ByteBuffer.allocate(command.getBytes().length); try { byteBuffer.put(command.getBytes("ASCII")); onWritable(byteBuffer); Thread.sleep(((BigDecimal) getConfig().get(RESPONSE_TIME_OUT)).intValue()); return onReadable(((BigDecimal) getConfig().get(BUFFER_SIZE)).intValue(), true); } catch (UnsupportedEncodingException | NumberFormatException | InterruptedException e) { Thread.currentThread().interrupt(); logger.debug( "An exception occurred while sending a command to the IRtrans transceiver for '{}': {}", getThing().getUID(), e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); } } return null; } private Runnable pollingRunnable = new Runnable() { @Override public void run() { while (true) { try { if (socketChannel == null) { previousConnectionState = false; onConnectionLost(); } else { if (!previousConnectionState && socketChannel.isConnected()) { previousConnectionState = true; onConnectionResumed(); } if (previousConnectionState && !socketChannel.isConnected() && !socketChannel.isConnectionPending()) { previousConnectionState = false; onConnectionLost(); } if (!socketChannel.isConnectionPending() && !socketChannel.isConnected()) { previousConnectionState = false; logger.debug("Disconnecting '{}' because of a network error", getThing().getUID()); socketChannel.close(); Thread.sleep(1000 * ((BigDecimal) getConfig().get(RECONNECT_INTERVAL)).intValue()); establishConnection(); } long stamp = System.currentTimeMillis(); if (!InetAddress.getByName(((String) getConfig().get(IP_ADDRESS))) .isReachable(((BigDecimal) getConfig().get(PING_TIME_OUT)).intValue())) { logger.debug( "Ping timed out after '{}' milliseconds. Disconnecting '{}' because of a ping timeout", System.currentTimeMillis() - stamp, getThing().getUID()); socketChannel.close(); } onConnectable(); ByteBuffer buffer = onReadable(((BigDecimal) getConfig().get(BUFFER_SIZE)).intValue(), false); if (buffer != null && buffer.remaining() > 0) { onRead(buffer); } } onAcceptable(); if (!Thread.currentThread().isInterrupted()) { Thread.sleep(LISTENING_INTERVAL); } else { return; } } catch (IOException e) { logger.trace("An exception occurred while polling the transceiver : '{}'", e.getMessage(), e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } }; protected void onAcceptable() { lock.lock(); try { try { selector.selectNow(); } catch (IOException e) { logger.debug("An exception occurred while selecting: {}", e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); } Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey selKey = it.next(); it.remove(); if (selKey.isValid()) { if (selKey.isAcceptable() && selKey == listenerKey) { try { SocketChannel newChannel = listenerChannel.accept(); newChannel.configureBlocking(false); logger.trace("Received a connection request from '{}'", newChannel.getRemoteAddress()); synchronized (selector) { selector.wakeup(); newChannel.register(selector, newChannel.validOps()); } } catch (IOException e) { logger.debug("An exception occurred while accepting a connection on channel '{}': {}", listenerChannel, e.getMessage()); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); } } } } } finally { lock.unlock(); } } protected void onConnectable() { lock.lock(); SocketChannel aSocketChannel = null; try { synchronized (selector) { selector.selectNow(); } Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey selKey = it.next(); it.remove(); if (selKey.isValid() && selKey.isConnectable()) { aSocketChannel = (SocketChannel) selKey.channel(); aSocketChannel.finishConnect(); logger.trace("The channel for '{}' is connected", aSocketChannel.getRemoteAddress()); } } } catch (IOException | NoConnectionPendingException e) { if (aSocketChannel != null) { logger.debug("Disconnecting '{}' because of a socket error : '{}'", getThing().getUID(), e.getMessage(), e); try { aSocketChannel.close(); } catch (IOException e1) { logger.debug("An exception occurred while closing the channel '{}': {}", socketChannel, e1.getMessage()); } } } finally { lock.unlock(); } } protected ByteBuffer onReadable(int bufferSize, boolean isSelective) { lock.lock(); try { synchronized (selector) { try { selector.selectNow(); } catch (IOException e) { logger.error("An exception occurred while selecting: {}", e.getMessage()); } } Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey selKey = it.next(); it.remove(); if (selKey.isValid() && selKey.isReadable()) { SocketChannel aSocketChannel = (SocketChannel) selKey.channel(); if ((aSocketChannel.equals(socketChannel) && isSelective) || !isSelective) { ByteBuffer readBuffer = ByteBuffer.allocate(bufferSize); int numberBytesRead = 0; boolean error = false; try { numberBytesRead = aSocketChannel.read(readBuffer); } catch (NotYetConnectedException e) { logger.warn("The channel '{}' is not yet connected: {}", aSocketChannel, e.getMessage()); if (!aSocketChannel.isConnectionPending()) { error = true; } } catch (IOException e) { // If some other I/O error occurs logger.warn("An IO exception occured on channel '{}': {}", aSocketChannel, e.getMessage()); error = true; } if (numberBytesRead == -1) { error = true; } if (error) { logger.debug("Disconnecting '{}' because of a socket error", getThing().getUID()); try { aSocketChannel.close(); } catch (IOException e1) { logger.debug("An exception occurred while closing the channel '{}': {}", socketChannel, e1.getMessage()); } } else { readBuffer.flip(); return readBuffer; } } } } return null; } finally { lock.unlock(); } } protected void onWritable(ByteBuffer buffer) { lock.lock(); try { synchronized (selector) { try { selector.selectNow(); } catch (IOException e) { logger.error("An exception occurred while selecting: {}", e.getMessage()); } } Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey selKey = it.next(); it.remove(); if (selKey.isValid() && selKey.isWritable()) { SocketChannel aSocketChannel = (SocketChannel) selKey.channel(); if (aSocketChannel.equals(socketChannel)) { boolean error = false; buffer.rewind(); try { logger.trace("Sending '{}' on the channel '{}'->'{}'", new String(buffer.array()), aSocketChannel.getLocalAddress(), aSocketChannel.getRemoteAddress()); aSocketChannel.write(buffer); } catch (NotYetConnectedException e) { logger.warn("The channel '{}' is not yet connected: {}", aSocketChannel, e.getMessage()); if (!aSocketChannel.isConnectionPending()) { error = true; } } catch (ClosedChannelException e) { // If some other I/O error occurs logger.warn("The channel for '{}' is closed: {}", aSocketChannel, e.getMessage()); error = true; } catch (IOException e) { // If some other I/O error occurs logger.warn("An IO exception occured on channel '{}': {}", aSocketChannel, e.getMessage()); error = true; } if (error) { try { aSocketChannel.close(); } catch (IOException e) { logger.warn("An exception occurred while closing the channel '{}': {}", aSocketChannel, e.getMessage()); } } } } } } finally { lock.unlock(); } } protected void onRead(ByteBuffer byteBuffer) { try { if (logger.isTraceEnabled()) { logger.trace("Received bytebuffer : '{}'", HexUtils.bytesToHex(byteBuffer.array())); } int byteCount = getByteCount(byteBuffer); while (byteCount > 0) { byte[] message = new byte[byteCount]; byteBuffer.get(message, 0, byteCount); if (logger.isTraceEnabled()) { logger.trace("Received message : '{}'", HexUtils.bytesToHex(message)); } String strippedBuffer = stripByteCount(ByteBuffer.wrap(message)); if (strippedBuffer != null) { String strippedMessage = strippedBuffer.split("\0")[0]; // IRTrans devices return "RESULT OK" when it succeeds to emit an // infrared sequence if (strippedMessage.contains("RESULT OK")) { parseOKMessage(strippedMessage); } // IRTrans devices return a string starting with RCV_HEX each time // it captures an infrared sequence from a remote control if (strippedMessage.contains("RCV_HEX")) { parseHexMessage(strippedMessage); } // IRTrans devices return a string starting with RCV_COM each time // it captures an infrared sequence from a remote control that is stored in the device's internal dB if (strippedMessage.contains("RCV_COM")) { parseIRDBMessage(strippedMessage); } byteCount = getByteCount(byteBuffer); } else { logger.warn("Received some non-compliant garbage '{}' - Parsing is skipped", new String(byteBuffer.array())); } } } catch (Exception e) { logger.error("An exception occurred while reading bytebuffer '{}' : {}", HexUtils.bytesToHex(byteBuffer.array()), e.getMessage(), e); } } protected int getByteCount(ByteBuffer byteBuffer) { String response = new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit()); response = StringUtils.chomp(response); Matcher matcher = RESPONSE_PATTERN.matcher(response); if (matcher.matches()) { return Integer.parseInt(matcher.group(1)); } return 0; } protected String stripByteCount(ByteBuffer byteBuffer) { String message = null; String response = new String(byteBuffer.array(), 0, byteBuffer.limit()); response = StringUtils.chomp(response); Matcher matcher = RESPONSE_PATTERN.matcher(response); if (matcher.matches()) { String byteCountAsString = matcher.group(1); message = matcher.group(2); } return message; } protected void parseOKMessage(String message) { // Nothing to do here } protected void parseHexMessage(String message) { Matcher matcher = HEX_PATTERN.matcher(message); if (matcher.matches()) { String command = matcher.group(1); IrCommand theCommand = null; for (IrCommand aCommand : irCommands) { if (aCommand.sequenceToHEXString().equals(command)) { theCommand = aCommand; break; } } if (theCommand != null) { for (TransceiverStatusListener listener : transceiverStatusListeners) { listener.onCommandReceived(this, theCommand); } } else { logger.error("{} does not match any know infrared command", command); } } else { logger.error("{} does not match the infrared message format '{}'", message, matcher.pattern()); } } protected void parseIRDBMessage(String message) { Matcher matcher = IRDB_PATTERN.matcher(message); if (matcher.matches()) { IrCommand command = new IrCommand(); command.setRemote(matcher.group(1)); command.setCommand(matcher.group(2)); for (TransceiverStatusListener listener : transceiverStatusListeners) { listener.onCommandReceived(this, command); } } else { logger.error("{} does not match the IRDB infrared message format '{}'", message, matcher.pattern()); } } /** * "Pack" the infrared command so that it can be sent to the IRTrans device * * @param led the led * @param command the the command * @return a string which is the full command to be sent to the device */ protected String packIRDBCommand(Led led, IrCommand command) { String output = new String(); output = "Asnd "; output += command.getRemote(); output += ","; output += command.getCommand(); output += ",l"; output += led.toString(); output += "\r\n"; return output; } /** * "Pack" the infrared command so that it can be sent to the IRTrans device * * @param led the led * @param command the the command * @return a string which is the full command to be sent to the device */ protected String packHexCommand(Led led, IrCommand command) { String output = new String(); output = "Asndhex "; output += "L"; output += led.toString(); output += ","; output += "H" + command.toHEXString(); output += (char) 13; return output; } }