/** * 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.dmx.internal.core; import java.util.TimerTask; import org.openhab.binding.dmx.DmxConnection; import org.openhab.binding.dmx.DmxService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DmxTransmitter, which is responsible for continuously sending all value * changes to the DMX connection. * * This transmitter should always run in a separate thread to allow for smooth * transmissions. * * @author Davy Vanherbergen * @since 1.2.0 */ public final class DmxTransmitter extends TimerTask { /* REPEAT_INTERVAL is 750 ms (results in 800-1000ms) repetition time */ private static final int REPEAT_INTERVAL = 750; private static final int REPEAT_COUNT = 3; public enum DmxRepeatMode { ALWAYS("always"), NEVER("never"), REDUCED("reduced"); private String repeatMode; DmxRepeatMode(String repeatMode) { this.repeatMode = repeatMode; } @Override public String toString() { return this.repeatMode; } public static DmxRepeatMode fromString(String repeatMode) { if (repeatMode != null) { for (DmxRepeatMode mode : DmxRepeatMode.values()) { if (repeatMode.equalsIgnoreCase(mode.repeatMode)) { return mode; } } } return null; } } private static Logger logger = LoggerFactory.getLogger(DmxTransmitter.class); private DmxUniverse universe = new DmxUniverse(); private DmxService service; private boolean running; private DmxRepeatMode repeatMode = DmxRepeatMode.ALWAYS; private boolean suspended; private long lastTransmit = 0; private int packetRepeatCount = 0; /** * Default constructor. */ public DmxTransmitter(DmxService service) { this.service = service; } /** * @{inheritDoc */ @Override public void run() { if (suspended) { return; } running = true; try { long now = System.currentTimeMillis(); byte[] b = universe.calculateBuffer(); DmxConnection conn = service.getConnection(); if (conn != null) { if (universe.getBufferChanged()) { logger.trace("DMX Buffer changed, also sending status updates"); conn.sendDmx(b); universe.notifyStatusListeners(); lastTransmit = now; packetRepeatCount = 0; } else if (repeatMode == DmxRepeatMode.ALWAYS) { logger.trace("repeat mode always, sending DMX only"); conn.sendDmx(b); lastTransmit = now; } else if ((repeatMode == DmxRepeatMode.REDUCED) && ((packetRepeatCount < REPEAT_COUNT) || ((now - lastTransmit) > REPEAT_INTERVAL))) { logger.trace("output needs refresh, sending DMX only"); conn.sendDmx(b); if (packetRepeatCount < REPEAT_COUNT) { packetRepeatCount++; } lastTransmit = now; } else { logger.trace("DMX output suppressed"); } } } catch (Exception e) { logger.error("Error sending dmx values.", e); } finally { running = false; } } /** * @return true if the transmitter is calculating values and transmitting */ public boolean isRunning() { return running; } /** * Suspend/resume transmitting. * * @param suspend * true to suspend */ public void setSuspend(boolean suspend) { this.suspended = suspend; } /** * change transmitter refresh cycle * * @param refreshInterval * interval in ms (if output did not change) */ public void setRepeatMode(DmxRepeatMode repeatMode) { this.repeatMode = repeatMode; } /** * Get the DMX channel in the current universe. * * @param channel * number * @return DMX channel */ public DmxChannel getChannel(int channel) { return universe.getChannel(channel); } /** * @return DMX universe */ public DmxUniverse getUniverse() { return universe; } }