/* =================================================================== * SmaChannel.java * * Created Sep 7, 2009 10:24:55 AM * * Copyright (c) 2009 Solarnetwork.net Dev Team. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * =================================================================== */ package net.solarnetwork.node.hw.sma.protocol; import java.util.EnumMap; import java.util.Map; /** * SMA channel object. * * @author matt * @version 1.0 */ public final class SmaChannel { private final short index; private final SmaChannelType type; private final SmaChannelTypeGroup typeGroup; private final int dataFormat; private final int accessLevel; private final String name; private final int dataLength; private Map<SmaChannelParam, Object> parameters; /** * Construct from raw data. * * <p> * Decode a SmaChannel from a raw byte sequence, using the following format: * </p> * * <pre> * # 1 index byte * # 1 channel type bytes * # 1 channel type group bytes * # 2 data format bytes * # 2 access level * # 16 channel name bytes * </pre> * * @param data * the raw packet byte data to decode * @param offset * the offset within the packet byte data to start decoding at */ public SmaChannel(byte[] data, int offset) { index = (short) (0xFF & data[offset]); type = SmaChannelType.forCode(0xFF & data[offset + 1]); typeGroup = SmaChannelTypeGroup.forCode(0xFF & data[offset + 2]); dataFormat = (0xFF & data[offset + 3]) | ((0xFF & data[offset + 4]) << 8); accessLevel = (0xFF & data[offset + 5]) | ((0xFF & data[offset + 6]) << 8); name = SmaUtils.parseString(data, offset + 7, 16); dataLength = 23 + decodeData(data, offset + 23); } /** * Get an individual parameter value. * * @param paramType * the channel parameter to get * @return the value, or <em>null</em> if not available */ public Object getParameterValue(SmaChannelParam paramType) { if ( parameters != null ) { return parameters.get(paramType); } return null; } @Override public String toString() { return "SmaChannel{name=" + name + ",type=" + type + ",index=" + index + ",group=" + typeGroup + ",accessLevel=" + accessLevel + ",format=" + dataFormat + ",dataLength=" + dataLength + (parameters == null ? "" : ",parameters=" + parameters) + '}'; } private int decodeData(byte[] data, int offset) { switch (this.type) { case Analog: return decodeAnalogData(data, offset); case Digital: return decodeDigitalData(data, offset); case Counter: return decodeCounterData(data, offset); case Status: return decodeStatusData(data, offset); default: return 0; } } /* * 8 unit bytes (char) 4 gain bytes (float) 4 offset bytes (float) */ private int decodeAnalogData(byte[] data, int offset) { addParameter(SmaChannelParam.Unit, SmaUtils.parseString(data, offset, 8)); addParameter(SmaChannelParam.Gain, SmaUtils.parseFloat(data, offset + 8)); addParameter(SmaChannelParam.Offset, SmaUtils.parseFloat(data, offset + 12)); return 16; } /* * 16 text_low bytes (char) 16 text_low bytes (char) */ private int decodeDigitalData(byte[] data, int offset) { addParameter(SmaChannelParam.TextLow, SmaUtils.parseString(data, offset, 16)); addParameter(SmaChannelParam.TextHigh, SmaUtils.parseString(data, offset + 16, 16)); return 32; } /* * 8 unit bytes (char) 4 gain bytes (float) */ private int decodeCounterData(byte[] data, int offset) { addParameter(SmaChannelParam.Unit, SmaUtils.parseString(data, offset, 8)); addParameter(SmaChannelParam.Gain, SmaUtils.parseFloat(data, offset + 8)); return 12; } /* * 2 status size bytes (int) X status bytes (char) */ private int decodeStatusData(byte[] data, int offset) { int size = (0xFF & data[offset]) | ((0xFF & data[offset + 1]) << 8); addParameter(SmaChannelParam.Status, SmaUtils.parseString(data, offset + 2, size)); return 2 + size; } private void addParameter(SmaChannelParam type, Object value) { if ( parameters == null ) { parameters = new EnumMap<SmaChannelParam, Object>(SmaChannelParam.class); } parameters.put(type, value); } public short getIndex() { return index; } public SmaChannelType getType() { return type; } public SmaChannelTypeGroup getTypeGroup() { return typeGroup; } public int getDataFormat() { return dataFormat; } public int getAccessLevel() { return accessLevel; } public String getName() { return name; } public int getDataLength() { return dataLength; } public Map<SmaChannelParam, Object> getParameters() { return parameters; } }