/** * 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.powermax.internal.message; import java.lang.reflect.InvocationTargetException; import javax.xml.bind.DatatypeConverter; import org.openhab.binding.powermax.internal.state.PowerMaxState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A base class for handling a message with the Visonic alarm system * * @author Laurent Garnier * @since 1.9.0 */ public class PowerMaxBaseMessage { private static final Logger logger = LoggerFactory.getLogger(PowerMaxBaseMessage.class); private byte[] rawData; private int code; private PowerMaxSendType sendType; private PowerMaxReceiveType receiveType; /** * Constructor. * * @param message * the message as a buffer of bytes */ public PowerMaxBaseMessage(byte[] message) { this.sendType = null; decodeMessage(message); } /** * Constructor. * * @param sendType * the type of a message to be sent */ public PowerMaxBaseMessage(PowerMaxSendType sendType) { this(sendType, null); } /** * Constructor. * * @param sendType * the type of a message to be sent * @param param * the dynamic part of a message to be sent; null if no dynamic part */ public PowerMaxBaseMessage(PowerMaxSendType sendType, byte[] param) { this.sendType = sendType; byte[] message = new byte[sendType.getMessage().length + 3]; int index = 0; message[index++] = 0x0D; for (int i = 0; i < sendType.getMessage().length; i++) { if ((param != null) && (sendType.getParamPosition() != null) && (i >= sendType.getParamPosition()) && (i < (sendType.getParamPosition() + param.length))) { message[index++] = param[i - sendType.getParamPosition()]; } else { message[index++] = sendType.getMessage()[i]; } } message[index++] = 0x00; message[index++] = 0x0A; decodeMessage(message); } /** * Extract information from the buffer of bytes and set class attributes * * @param data * the message as a buffer of bytes */ private void decodeMessage(byte[] data) { rawData = data; code = rawData[1] & 0x000000FF; try { receiveType = PowerMaxReceiveType.fromCode((byte) code); } catch (IllegalArgumentException arg0) { receiveType = null; } } /** * Work to be done when receiving a message from the Visonic alarm system * * @return a new state containing all changes driven by the message */ public PowerMaxState handleMessage() { // Send an ACK if needed if (isAckRequired()) { PowerMaxCommDriver.getTheCommDriver().sendAck(this, (byte) 0x02); } if (logger.isDebugEnabled()) { logger.debug("{}message handled by class {}: {}", (receiveType == null) ? "Unsupported " : "", this.getClass().getSimpleName(), this.toString()); } return null; } /** * @return the raw data of the message (buffer of bytes) */ public byte[] getRawData() { return rawData; } /** * @return the identifying code of the message (second byte in the buffer) */ public int getCode() { return code; } /** * @return the type of the message to be sent */ public PowerMaxSendType getSendType() { return sendType; } /** * @return the type of the received message */ public PowerMaxReceiveType getReceiveType() { return receiveType; } /** * @return true if the received message requires the sending of an ACK */ public boolean isAckRequired() { return receiveType == null || receiveType.isAckRequired(); } @Override public String toString() { String str = "\n - Raw data = " + DatatypeConverter.printHexBinary(rawData); str += "\n - type = " + String.format("%02X", code); if (sendType != null) { str += " ( " + sendType.toString() + " )"; } else if (receiveType != null) { str += " ( " + receiveType.toString() + " )"; } return str; } /** * Instantiate a class for handling a received message The class depends on the message. * * @param message * the received message as a buffer of bytes * * @return a new class instance */ public static PowerMaxBaseMessage getMessageObject(byte[] message) { Class<?> cl; try { cl = PowerMaxReceiveType.fromCode(message[1]).getHandlerClass(); } catch (IllegalArgumentException e) { cl = PowerMaxBaseMessage.class; } try { return (PowerMaxBaseMessage) cl.getConstructor(byte[].class).newInstance(message); } catch (InstantiationException e) { return new PowerMaxBaseMessage(message); } catch (IllegalAccessException e) { return new PowerMaxBaseMessage(message); } catch (NoSuchMethodException e) { return new PowerMaxBaseMessage(message); } catch (InvocationTargetException e) { return new PowerMaxBaseMessage(message); } } }