package com.rusefi.can.reader.dbc; import com.rusefi.can.CANPacket; public class DbcField { private String name; private final int startOffset; private final int length; private final double mult; private final double offset; private String category; private final boolean isBigEndian; private boolean isNiceName; public DbcField(String name, int startOffset, int length, double mult, double offset, String category, boolean isBigEndian) { this.name = name; this.startOffset = startOffset; this.length = length; this.mult = mult; this.offset = offset; this.category = category; this.isBigEndian = isBigEndian; } public static DbcField parseField(DbcPacket parent, String line) { line = DbcFile.replaceSpecialWithSpaces(line); String[] tokens = line.split(" "); if (tokens.length < 2) return null; String name = tokens[1]; int index = 1; try { while (!tokens[index - 1].equals(":")) index++; } catch (ArrayIndexOutOfBoundsException e) { throw new IllegalStateException("While parsing [" + line + "]", e); } if (DbcFile.debugEnabled) System.out.println(line); int startOffset; try { startOffset = Integer.parseInt(tokens[index]); } catch (NumberFormatException e) { throw new IllegalStateException("While " + line, e); } int length = Integer.parseInt(tokens[index + 1]); int endiannessCode = Integer.parseInt(tokens[index + 2]); if (endiannessCode != 0 && endiannessCode != 1) throw new IllegalStateException("Unexpected endiannessCode " + endiannessCode); boolean isBigEndian = endiannessCode == 0; double mult = Double.parseDouble(tokens[index + 3]); double offset = Double.parseDouble(tokens[index + 4]); return new DbcField(name, startOffset, length, mult, offset, parent.getName(), isBigEndian); } public String getCategory() { return category; } public boolean isNiceName() { return isNiceName; } public String getName() { return name; } public int getStartOffset() { return startOffset; } public int getLength() { return length; } public double getMult() { return mult; } public double getOffset() { return offset; } public boolean isBigEndian() { return isBigEndian; } @Override public String toString() { return "DbcField{" + "name='" + name + '\'' + ", startOffset=" + startOffset + ", length=" + length + ", mult=" + mult + ", isBigEndian=" + isBigEndian + '}'; } public static int getBitRange(byte[] data, int bitIndex, int bitWidth, boolean isBigEndian) { if (bitIndex < 0) throw new IllegalArgumentException("Huh? " + bitIndex + " " + bitWidth); int byteIndex = bitIndex >> 3; int shift = bitIndex - byteIndex * 8; if (byteIndex >= data.length) return 0; int value = data[byteIndex] & 0xff; if (shift + bitWidth > 8) { int otherByteIndex = (isBigEndian ? -1 : +1) + byteIndex; if (otherByteIndex < 0 || otherByteIndex >= data.length) return 0; value = value + data[otherByteIndex] * 256; } int mask = (1 << bitWidth) - 1; return (value >> shift) & mask; } public double getValue(CANPacket packet) { return getBitRange(packet.getData(), startOffset, length, isBigEndian) * mult + offset; } public void rename(String niceName) { name = niceName; isNiceName = true; } public boolean coversByte(int byteIndex) { int startBit = byteIndex * 8; if (startOffset > startBit) return false; if (startOffset + length < startBit + 8) return false; return true; } }