/**
* 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.plugwise.protocol;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Acknowledge message class - ACKs are used in the PW protocol to serve different means, from acknowledging a message
* sent to the stick by the host, as well as confirmation messages from Circles in the network for various purposes
* Not all purposes are yet reverse-engineered
*
* @author Karel Goderis
* @since 1.1.0
*/
public class AcknowledgeMessage extends Message {
public enum ExtensionCode {
NOTEXTENDED(0),
SUCCESS(193),
ERROR(194),
CIRCLEPLUS(221),
CLOCKSET(215),
ON(216),
OFF(222),
TIMEOUT(225),
UNKNOWN(999);
private int identifier;
private ExtensionCode(int value) {
identifier = value;
}
private static final Map<Integer, ExtensionCode> typesByValue = new HashMap<Integer, ExtensionCode>();
static {
for (ExtensionCode type : ExtensionCode.values()) {
typesByValue.put(type.identifier, type);
}
}
public static ExtensionCode forValue(int value) {
return typesByValue.get(value);
}
public int toInt() {
return identifier;
}
}
private static final Pattern SHORT_RESPONSE_PATTERN = Pattern.compile("(\\w{4})");
private static final Pattern EXTENDED_RESPONSE_PATTERN = Pattern.compile("(\\w{4})(\\w{16})");
private ExtensionCode code;
private String extendedMAC = "";
public AcknowledgeMessage(int sequenceNumber, String payLoad) {
super(sequenceNumber, payLoad);
type = MessageType.ACKNOWLEDGEMENT;
MAC = "";
}
public AcknowledgeMessage(String payLoad) {
super(payLoad);
type = MessageType.ACKNOWLEDGEMENT;
MAC = "";
}
@Override
protected void parsePayLoad() {
Matcher shortMatcher = SHORT_RESPONSE_PATTERN.matcher(payLoad);
Matcher extendedMatcher = EXTENDED_RESPONSE_PATTERN.matcher(payLoad);
if (extendedMatcher.matches()) {
code = ExtensionCode.forValue(Integer.parseInt(extendedMatcher.group(1), 16));
if (code == null) {
code = ExtensionCode.UNKNOWN;
}
extendedMAC = extendedMatcher.group(2);
} else if (shortMatcher.matches()) {
code = ExtensionCode.forValue(Integer.parseInt(shortMatcher.group(1), 16));
if (code == null) {
code = ExtensionCode.UNKNOWN;
}
} else {
logger.debug("Plugwise protocol AcknowledgeMessage error: {} does not match", payLoad);
code = ExtensionCode.UNKNOWN;
}
}
public boolean isSuccess() {
if (code == ExtensionCode.SUCCESS) {
return true;
} else {
return false;
}
}
public boolean isError() {
if (code == ExtensionCode.ERROR) {
return true;
} else {
return false;
}
}
public boolean isTimeOut() {
if (code == ExtensionCode.TIMEOUT) {
return true;
} else {
return false;
}
}
public boolean isExtended() {
if (code != ExtensionCode.NOTEXTENDED && code != ExtensionCode.SUCCESS && code != ExtensionCode.ERROR) {
return true;
} else {
return false;
}
}
public ExtensionCode getExtensionCode() {
if (isExtended()) {
return code;
} else {
return ExtensionCode.NOTEXTENDED;
}
}
public String getExtendedMAC() {
if (isExtended()) {
return extendedMAC;
} else {
return null;
}
}
public String getCirclePlusMAC() {
if (isExtended() && code == ExtensionCode.CIRCLEPLUS) {
return extendedMAC;
} else {
return null;
}
}
public boolean isOn() {
if (isExtended() && code == ExtensionCode.ON) {
return true;
} else {
return false;
}
}
public boolean isOff() {
if (isExtended() && code == ExtensionCode.OFF) {
return true;
} else {
return false;
}
}
@Override
public String getPayLoad() {
return payLoadToHexString();
}
@Override
protected String payLoadToHexString() {
switch (code) {
case CIRCLEPLUS:
return String.format("%04X", code.toInt()) + extendedMAC;
case ON:
return String.format("%04X", code.toInt()) + extendedMAC;
case OFF:
return String.format("%04X", code.toInt()) + extendedMAC;
default:
return String.format("%04X", code.toInt());
}
}
}