package org.opennaas.extensions.roadm.wonesys.commandsets; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Wonesys messages are byte chunks with the following format: * * Header (2B) | DeviceID (2B) | Reserved (2B) | CommandID (2B) | Reserved (4B) | DataLength (2B) | Data | XOR (1B) | EOS (1B) * * @author isart * */ public final class WonesysMessage { /** The logger **/ Log log = LogFactory.getLog(WonesysMessage.class); private static final String HEADER = "5910"; private static final String RESERVED = "ffff"; private static final String EOS = "00"; private static final int deviceIDIndex = 2; private static final int commandIDIndex = 6; private static final int dataLengthIndex = 12; private static final int dataIndex = 14; /** * Length of the shortest valid command: 14 bytes + 0 bytes (data) + XOR + EOS */ private static final int MIN_COMMAND_LENGTH = (dataIndex + 0 + 1 + 1) * 2; private final String msg; public WonesysMessage(String completeMsg) throws Exception { checkCorrectiviness(completeMsg); this.msg = completeMsg; } public WonesysMessage(String deviceId, String commandId, String data) { this(deviceId, commandId, getDataLength(data), data); } public WonesysMessage(String deviceId, String commandId, String dataLength, String data, boolean checkDataLength) throws Exception { this(deviceId, commandId, dataLength, data); if (checkDataLength) { if (!dataLength.equals(getDataLength(data))) throw new Exception("Given data does not match required data length"); } } private WonesysMessage(String deviceId, String commandId, String dataLength, String data) { StringBuilder builder = new StringBuilder(); builder.append(HEADER); builder.append(deviceId); builder.append(RESERVED); builder.append(commandId); builder.append(RESERVED); builder.append(RESERVED); builder.append(dataLength); builder.append(data); String cmbBase = builder.toString(); String xor = getXOR(cmbBase); builder.append(xor); builder.append(EOS); this.msg = builder.toString(); log.info("Created WonesysMessage " + this.msg); } public String getDeviceId() { return this.msg.substring(deviceIDIndex * 2, deviceIDIndex * 2 + 2 * 2); } public String getCommandId() { return this.msg.substring(commandIDIndex * 2, commandIDIndex * 2 + 2 * 2); } public String getData() { String dataLengthStr = this.msg.substring(dataLengthIndex * 2, dataLengthIndex * 2 + 2 * 2); // transform str into real byte length // Invert byte order (Big endian stuff) String datasizeStr = dataLengthStr.substring(2, 4) + dataLengthStr.substring(0, 2); int dataLength = Integer.parseInt(datasizeStr, 16); return this.msg.substring(dataIndex * 2, dataIndex * 2 + dataLength * 2); } public String toString() { return this.msg; } // private static String getDataLength(String data) { // // XXX: This works only for data smaller than 16 bytes // String dataLength = "00"; // if (data.length() > 0) { // dataLength = Integer.toHexString((data.length() / 2) + 1); // if (dataLength.length() < 2) { // dataLength = "0" + dataLength; // } // } // dataLength += "00"; // // return dataLength; // } /** * * @param data * @return data length as an HexString in BigEndian. Returned String must be 4 chars long */ private static String getDataLength(String data) { String dataLength = Integer.toHexString(data.length() / 2); // add trailing 0's if (dataLength.length() % 2 != 0) // odd dataLength.length() dataLength = "0" + dataLength; if (dataLength.length() < 4) dataLength = "00" + dataLength; // to big endian dataLength = dataLength.substring(2, 4) + dataLength.substring(0, 2); return dataLength; } private String getXOR(String cmd) { int xor = Integer.parseInt(cmd.substring(0, 2), 16) ^ Integer.parseInt(cmd.substring(2, 4), 16); for (int i = 4; i <= cmd.length() - 2; i++) { xor = xor ^ Integer.parseInt(cmd.substring(i, i + 2), 16); i++; } String hxor = Integer.toHexString(xor); if (hxor.length() < 2) { hxor = "0" + hxor; } return hxor; } private void checkCorrectiviness(String command) throws Exception { // TODO: Enhance checking, throw specific exceptions if (command.length() < WonesysMessage.MIN_COMMAND_LENGTH) throw new Exception("Malformed message [" + command + "]"); } }