/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2010, Wolfgang Puffitsch <wpuffits@mail.tuwien.ac.at> 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 3 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, see <http://www.gnu.org/licenses/>. */ package cruiser.common; public abstract class WireMessage { public enum Type { SPEED_FRONT_LEFT(1, 4), SPEED_FRONT_RIGHT(2, 4), SPEED_REAR_LEFT(3, 4), SPEED_REAR_RIGHT(4, 4), TARGET_SPEED(7, 8), THROTTLE(8, 4), BRAKE(9, 4); final int id; final int length; Type(int id, int length) { this.id = id; this.length = length; } // reverse lookup; take care when adding new members! public static Type fromId(int id) { switch(id) { case 1: return SPEED_FRONT_LEFT; case 2: return SPEED_FRONT_RIGHT; case 3: return SPEED_REAR_LEFT; case 4: return SPEED_REAR_RIGHT; case 7: return TARGET_SPEED; case 8: return THROTTLE; case 9: return BRAKE; default: return null; } } } // common field for all subtypes private final Type type; WireMessage(Type type) { this.type = type; } public Type getType() { return type; } private static final int OVERHEAD_LENGTH = 7; public static final int MAX_LENGTH = 15+OVERHEAD_LENGTH; static String buildMessage(Type type, long data) { char[] buffer = new char[OVERHEAD_LENGTH+type.length]; int pos = 0; buffer[pos++] = ':'; buffer[pos++] = hexDigit((type.id >>> 4) & 0x0f); buffer[pos++] = hexDigit(type.id & 0x0f); buffer[pos++] = hexDigit(type.length); int checksum = (type.id >>> 4) ^ type.id ^ type.length; for (int i = type.length-1; i >= 0; i--) { //@WCA loop <= 15 int d = (int)(data >>> (4*i)); buffer[pos++] = hexDigit(d & 0x0f); checksum ^= d; } buffer[pos++] = hexDigit(checksum & 0x0f); buffer[pos++] = '\r'; buffer[pos] = '\n'; return new String(buffer); } public static boolean checkMessage(String msg) { // check message start if (msg.charAt(0) != ':') { // System.err.print("^"); return false; } // check type Type t = parseType(msg); if (t == null) { // System.err.print("T"); return false; } // check length of payload int len = parseLength(msg); if (len < 0 || len != t.length) { // System.err.print("L"); return false; } // check length of overall message if (msg.length() != len+OVERHEAD_LENGTH) { // System.err.print("S"); return false; } // checking checksum int chk = 0; int chkpos = msg.length()-3; for (int i = 1; i < chkpos; i++) { //@WCA loop <= 18 chk ^= hexNum(msg.charAt(i)); } if (hexDigit(chk) != msg.charAt(chkpos)) { // System.err.print("C"); return false; } // check message end if (msg.charAt(msg.length()-2) != '\r') { // System.err.print("R"); return false; } if (msg.charAt(msg.length()-1) != '\n') { // System.err.print("N"); return false; } return true; } public static Type parseType(String msg) { int a = hexNum(msg.charAt(1)); int b = hexNum(msg.charAt(2)); if (a < 0 || b < 0) { return null; } int t = (a << 4) | (b & 0x0f); return Type.fromId(t); } public static int parseLength(String msg) { int a = hexNum(msg.charAt(3)); return a; } public static long parseData(String msg, int len) { long data = 0; for (int i = 0; i < len; i++) { //@WCA loop <= 15 int a = hexNum(msg.charAt(4+i)); if (a < 0) { return -1; } data <<= 4; data |= a & 0x0f; } return data; } private static char hexDigit(int v) { if (v >= 0 && v <= 9) { return (char)(v+'0'); } if (v >= 10 && v <= 15) { return (char)(v-10+'A'); } return '#'; } private static int hexNum(char c) { if (c >= '0' && c <= '9') { return c-'0'; } if (c >= 'A' && c <= 'F') { return c-'A'+10; } if (c >= 'a' && c <= 'f') { return c-'a'+10; } return -1; } }