/** * Copyright (c) 2010-2016 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.nikobus.internal.core; import java.util.concurrent.LinkedBlockingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Command sender. Runs in dedicated thread to send commands asynchronously to * the Nikobus interface. * * @author Davy Vanherbergen * @since 1.3.0 */ public class NikobusCommandSender implements Runnable { private static Logger log = LoggerFactory.getLogger(NikobusCommandSender.class); private LinkedBlockingQueue<NikobusCommand> sendQueue = new LinkedBlockingQueue<NikobusCommand>(); private NikobusInterface serialInterface; private boolean stopped; /** * Create new instance linked to the given serial interface. * * @param serialInterface * Nikobus interface. */ public NikobusCommandSender(NikobusInterface serialInterface) { this.serialInterface = serialInterface; } /** * Start sending thread. */ @Override public void run() { log.debug("Command sender started."); try { while (true && !stopped) { NikobusCommand command = sendQueue.take(); if (command.getWaitForSilence()) { waitForQuietBus(); } log.trace("Sending command {}", command.getCommand()); for (int i = 0; i < command.getRepeats(); i++) { serialInterface.writeMessage(command.getCommand()); } command.incrementSentCount(); // leave a little time between consecutive commands Thread.sleep(50); } } catch (InterruptedException e) { log.debug("Command sender stopped."); } catch (Exception e) { log.error("Error writing command.", e); } } /** * Wait until there has been no activity on the bus in the last 150 ms. */ private void waitForQuietBus() { while (System.currentTimeMillis() - serialInterface.getLastEventTimestamp() < 150) { try { Thread.sleep(50); } catch (InterruptedException e) { break; } } } /** * Send a command to the Nikobus. Sending is done asynchronously. This * method will return immediately. * * @param cmd * command to send. */ public void sendCommand(NikobusCommand cmd) { if (isCommandRedundant(cmd)) { return; } sendQueue.add(cmd); } /** * Stop execution. */ public void stop() { stopped = true; } /** * Check if the sending of the command is redundant or not allowed. * * @param cmd Nikobus Command * @return true if the command is already scheduled for sending.. */ public boolean isCommandRedundant(NikobusCommand cmd) { if (!cmd.getAllowDuplicates() && sendQueue.contains(cmd)) { log.trace("Ignoring duplicate command {}", cmd.toString()); return true; } return false; } }