/** * 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.openenergymonitor.protocol; import java.util.HashMap; import java.util.Map.Entry; import org.openhab.binding.openenergymonitor.protocol.OpenEnergyMonitorParserRule.DataType; /** * Class for parse data packets from Open Energy Monitor devices. * * @author Pauli Anttila * @since 1.4.0 */ public class OpenEnergyMonitorDataParser { private HashMap<String, OpenEnergyMonitorParserRule> parsingRules = null; public OpenEnergyMonitorDataParser(HashMap<String, OpenEnergyMonitorParserRule> parsingRules) { this.parsingRules = parsingRules; } /** * Method to parse Open Energy Monitoring device datagram to variables by defined parsing rules. * * @param data datagram from Open Energy Monitoring device * * @return Hash table which contains all parsed variables. */ public HashMap<String, Number> parseData(byte[] data) { HashMap<String, Number> variables = new HashMap<String, Number>(); byte address = data[0]; for (Entry<String, OpenEnergyMonitorParserRule> entry : parsingRules.entrySet()) { OpenEnergyMonitorParserRule rule = entry.getValue(); if (rule.getAddress() == address) { Number obj = convertTo(rule.getDataType(), getBytes(rule.getParseBytes(), data)); variables.put(entry.getKey(), obj); } } return variables; } private byte[] getBytes(int[] byteIndexes, byte[] data) { byte[] bytes = new byte[byteIndexes.length]; for (int i = 0; i < byteIndexes.length; i++) { bytes[i] = data[byteIndexes[i]]; } return bytes; } private Number convertTo(DataType dataType, byte[] data) { Number val = null; switch (dataType) { case DOUBLE: val = toDouble(data); break; case FLOAT: val = toFloat(data); break; case S16: val = toShort(data); break; case S32: val = toInt(data); break; case S64: val = toLong(data); break; case S8: val = toByte(data); break; case U16: val = (int) (toShort(data) & 0xFFFF); break; case U32: val = (long) (toInt(data) & 0xFFFFFFFFL); break; case U8: val = (short) (toByte(data) & 0xFF); break; } return val; } public static byte toByte(byte[] data) { return (data == null || data.length == 0) ? 0x0 : data[0]; } public static short toShort(byte[] data) { // if (data == null || data.length != 2) return 0x0; return (short) ((0xff & data[0]) << 8 | (0xff & data[1]) << 0); } public static char toChar(byte[] data) { // if (data == null || data.length != 2) return 0x0; return (char) ((0xff & data[0]) << 8 | (0xff & data[1]) << 0); } public static int toInt(byte[] data) { // if (data == null || data.length != 4) return 0x0; return (0xff & data[0]) << 24 | (0xff & data[1]) << 16 | (0xff & data[2]) << 8 | (0xff & data[3]) << 0; } public static long toLong(byte[] data) { // if (data == null || data.length != 8) return 0x0; return (long) (0xff & data[0]) << 56 | (long) (0xff & data[1]) << 48 | (long) (0xff & data[2]) << 40 | (long) (0xff & data[3]) << 32 | (long) (0xff & data[4]) << 24 | (long) (0xff & data[5]) << 16 | (long) (0xff & data[6]) << 8 | (long) (0xff & data[7]) << 0; } public static float toFloat(byte[] data) { // if (data == null || data.length != 4) return 0x0; return Float.intBitsToFloat(toInt(data)); } public static double toDouble(byte[] data) { // if (data == null || data.length != 8) return 0x0; return Double.longBitsToDouble(toLong(data)); } public static boolean toBoolean(byte[] data) { return data[0] != 0x00; } }