/** * 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.ArrayList; import java.util.Collections; import java.util.List; import java.util.Vector; import org.openhab.binding.dmx.DmxStatusUpdateListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DMX Universe. Can contain up to 512 DMX channels. * * @author Davy Vanherbergen * @since 1.2.0 */ public class DmxUniverse { private static final Logger logger = LoggerFactory.getLogger(DmxUniverse.class); private Vector<DmxChannel> channels = new Vector<DmxChannel>(); private short[] buffer = new short[512]; private boolean bufferChanged = false; private int minimumBufferSize = 32; private List<DmxStatusUpdateListener> updateListeners = new ArrayList<DmxStatusUpdateListener>(); /** * Change the buffer value at the given index. * * @param index * @param value */ private void setBufferValue(int index, short value) { if (buffer[index] == value) { return; } else { buffer[index] = value; bufferChanged = true; } } /** * Calculate the current DMX buffer state. * * @return DMX buffer. */ public byte[] calculateBuffer() { bufferChanged = false; long calculationTime = System.currentTimeMillis(); for (DmxChannel channel : channels) { setBufferValue(channel.getChannelId() - 1, channel.getNextValue(calculationTime).shortValue()); } byte[] b = new byte[minimumBufferSize]; for (int i = 0; i < minimumBufferSize; i++) { b[i] = (byte) (buffer[i]); } return b; } /** * Add a new DMX channel. * * @param channel * to add. */ private synchronized void addChannel(DmxChannel channel) { logger.trace("Adding channel {}", channel.getChannelId()); channels.add(channel); Collections.sort(channels); if (channel.getChannelId() > minimumBufferSize) { minimumBufferSize = channel.getChannelId(); } } /** * @return true if the buffer was changed since the last calculation. */ public boolean getBufferChanged() { return bufferChanged; } /** * Find a channel by id. If it doesn't exist, it is created. * * @param channelId * int * @return channel */ public DmxChannel getChannel(int channelId) { for (DmxChannel c : channels) { if (c.getChannelId() == channelId) { return c; } } DmxChannel c = new DmxChannel(channelId); addChannel(c); return c; } /** * Clear all channel values. */ public void clear() { for (DmxChannel c : channels) { c.setValue(0); } } /** * Add a new status update listener, which can receive values when a channel * is changed. * * @param listener * status listener to add. */ public void addStatusListener(DmxStatusUpdateListener listener) { updateListeners.add(listener); } /** * Stop a given status update listener from receiving updates. * * @param listener * status listener to remove. */ public void removeStatusListener(DmxStatusUpdateListener listener) { updateListeners.remove(listener); } /** * Broadcast status update to all listeners. */ public void notifyStatusListeners() { for (DmxStatusUpdateListener listener : updateListeners) { if (System.currentTimeMillis() > listener.getLastUpdateTime() + listener.getUpdateDelay()) { int values[] = new int[listener.getFootPrint()]; for (int i = 0; i < listener.getFootPrint(); i++) { values[i] = getChannel(listener.getChannel() + i).getValue(); } listener.processStatusUpdate(values); } } } }