/* ===================================================================
* SmaUtils.java
*
* Created Sep 7, 2009 10:28:12 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.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Constants for SMA.
*
* @author matt
* @version 1.0
*/
public final class SmaUtils {
/** An empty byte array, useful for specifying empty user data. */
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
private static final Pattern STRING_TRIM_PAT = Pattern.compile("\\s+\\u0000?$");
private SmaUtils() {
// this class should not be constructed
}
/**
* Encode the user data value for a {@code SmaCommand.GetData} request
* packet.
*
* @param channel
* the channel to get the data for
* @return the user data value
*/
public static byte[] encodeGetDataRequestUserData(SmaChannel channel) {
byte[] result = new byte[3];
result[0] = (byte) channel.getType().getCode();
result[1] = (byte) channel.getTypeGroup().getCode();
result[2] = (byte) channel.getIndex();
return result;
}
/**
* Encode the user data value for a {@code SmaCommand.SetData} request
* packet for a specific channel and a integer value.
*
* <p>
* For {@code Analog} channel types, the value will be encoded as a 2-byte
* value. Otherwise a 4-byte value will be used.
* </p>
*
* @param channel
* the channel to set the data for
* @param value
* the data to encode
* @return the user data value (7 or 9 bytes long)
*/
public static byte[] encodeSetDataRequestUserData(SmaChannel channel, int value) {
byte[] result = new byte[channel.getType() == SmaChannelType.Analog ? 7 : 9];
result[0] = (byte) channel.getType().getCode();
result[1] = (byte) channel.getType().getCode();
result[2] = (byte) channel.getIndex();
result[3] = (byte) (channel.getType() == SmaChannelType.Analog ? 1 : 2);
result[4] = (byte) 0;
result[5] = (byte) (0xFF & value);
result[6] = (byte) (0xFF & (value >> 8));
if ( channel.getType() != SmaChannelType.Analog ) {
result[7] = (byte) (0xFF & (value >> 16));
result[8] = (byte) (0xFF & (value >> 24));
}
return result;
}
/**
* Parse an IEEE-754, little endian encoded float into a Float.
*
* <p>
* This method expects to read 4 bytes starting at the provided
* {@code offset}.
* </p>
*
* @param data
* the bytes
* @param offset
* the offset to read the float from
* @return a Float
*/
public static Float parseFloat(byte[] data, int offset) {
int bits = (0xFF & data[offset]) | ((0xFF & data[offset + 1]) << 8)
| ((0xFF & data[offset + 2]) << 16) | ((0xFF & data[offset + 3]) << 24);
return Float.intBitsToFloat(bits);
}
/**
* Parse an ASCII encoded String from bytes, removing trailing spaces and
* null character.
*
* @param data
* the byte data
* @param offset
* the offset to start reading the String from
* @param length
* the length to read
* @return a new String
*/
public static String parseString(byte[] data, int offset, int length) {
// create ASCII string and remove trailing spaces and null character
String s = null;
try {
s = new String(data, offset, length, "ASCII");
} catch ( UnsupportedEncodingException e ) {
// should not get here
}
if ( s != null ) {
Matcher m = STRING_TRIM_PAT.matcher(s);
s = m.replaceFirst("");
}
return s;
}
/**
* Turn an integer into a little-endian encoded byte array.
*
* @param value
* the integer to encode
* @return the byte array (4 bytes long)
*/
public static byte[] littleEndianBytes(int value) {
byte[] result = new byte[4];
result[0] = (byte) (0xFF & value);
result[1] = (byte) (0xFF & (value >> 8));
result[2] = (byte) (0xFF & (value >> 16));
result[3] = (byte) (0xFF & (value >> 24));
return result;
}
}