/** * 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.satel.command; import org.openhab.binding.satel.internal.event.EventDispatcher; import org.openhab.binding.satel.internal.protocol.SatelMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class for all command classes. * * @author Krzysztof Goworek * @since 1.7.0 */ public abstract class SatelCommandBase extends SatelMessage implements SatelCommand { private static final Logger logger = LoggerFactory.getLogger(SatelCommandBase.class); /** * Used in extended (INT-RS v2.xx) command version. */ protected static final byte[] EXTENDED_CMD_PAYLOAD = { 0x00 }; private static final byte COMMAND_RESULT_CODE = (byte) 0xef; private volatile State state = State.NEW; protected SatelMessage response; /** * Creates new command basing on command code and extended command flag. * * @param commandCode * command code * @param extended * if <code>true</code> command will be sent as extended (256 * zones or outputs) */ public SatelCommandBase(byte commandCode, boolean extended) { this(commandCode, extended ? EXTENDED_CMD_PAYLOAD : EMPTY_PAYLOAD); } /** * Creates new instance with specified command code and payload. * * @param command * command code * @param payload * command payload */ public SatelCommandBase(byte commandCode, byte[] payload) { super(commandCode, payload); } /** * {@inheritDoc} */ @Override public State getState() { return state; } /** * {@inheritDoc} */ @Override public void setState(State state) { synchronized (this) { this.state = state; this.notifyAll(); } } /** * {@inheritDoc} */ @Override public SatelMessage getRequest() { return this; } /** * {@inheritDoc} */ @Override public boolean handleResponse(EventDispatcher eventDispatcher, SatelMessage response) { // if response is valid, store it for future use if (response == null) { return false; } // TODO consider logging request and response messages for commands that failed if (response.getCommand() == COMMAND_RESULT_CODE) { if (!hasCommandSucceeded(response)) { return false; } } else if (!isResponseValid(response)) { return false; } this.response = response; return true; } /** * Checks whether given response is valid for the command. * * @param response message to check * @return <code>true</code> if given message is valid response for the command */ protected abstract boolean isResponseValid(SatelMessage response); protected static int bcdToInt(byte[] bytes, int offset, int size) { int result = 0, digit; int byteIdx = offset; int digits = size * 2; for (int i = 0; i < digits; ++i) { if (i % 2 == 0) { digit = (bytes[byteIdx] >> 4) & 0x0f; } else { digit = (bytes[byteIdx]) & 0x0f; byteIdx += 1; } result = result * 10 + digit; } return result; } protected static boolean hasCommandSucceeded(SatelMessage response) { // validate response message if (response.getCommand() != COMMAND_RESULT_CODE) { logger.error("Invalid response code: {}", response.getCommand()); return false; } if (response.getPayload().length != 1) { logger.error("Invalid payload length: {}", response.getPayload().length); return false; } // check result code byte responseCode = response.getPayload()[0]; String errorMsg; switch (responseCode) { case 0: // success return true; case 0x01: errorMsg = "Requesting user code not found"; break; case 0x02: errorMsg = "No access"; break; case 0x03: errorMsg = "Selected user does not exist"; break; case 0x04: errorMsg = "Selected user already exists"; break; case 0x05: errorMsg = "Wrong code or code already exists"; break; case 0x06: errorMsg = "Telephone code already exists"; break; case 0x07: errorMsg = "Changed code is the same"; break; case 0x08: errorMsg = "Other error"; break; case 0x11: errorMsg = "Can not arm, but can use force arm"; break; case 0x12: errorMsg = "Can not arm"; break; case (byte) 0xff: logger.trace("Command accepted"); return true; default: if (responseCode >= 0x80 && responseCode <= 0x8f) { errorMsg = String.format("Other error: %02X", responseCode); } else { errorMsg = String.format("Unknown result code: %02X", responseCode); } } logger.error(errorMsg); return false; } }