/** * Copyright (C) 2013 - 2015 the enviroCar community * * This file is part of the enviroCar app. * * The enviroCar app 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. * * The enviroCar app 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 the enviroCar app. If not, see http://www.gnu.org/licenses/. */ package org.envirocar.obd.commands; import org.envirocar.obd.commands.request.BasicCommand; import org.envirocar.obd.exception.AdapterSearchingException; import org.envirocar.obd.exception.InvalidCommandResponseException; import org.envirocar.obd.exception.NoDataReceivedException; import org.envirocar.obd.exception.UnmatchedResponseException; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; public class PIDSupported implements BasicCommand { private final byte[] output; private Set<PID> pids; private byte[] bytes; private String group; public PIDSupported() { this("00"); } /** * @param group the group of commands ("00", "20", "40" ...) */ public PIDSupported(String group) { this.output = "01 ".concat(group).getBytes(); this.group = group; } private String createHex(int i) { String result = Integer.toString(i, 16); if (result.length() == 1) result = "0".concat(result); return result; } public Set<PID> parsePIDs(byte[] rawData) throws InvalidCommandResponseException, NoDataReceivedException, UnmatchedResponseException, AdapterSearchingException { if (rawData == null) { throw new InvalidCommandResponseException("Null response on PIDSupported request"); } String rawAsString = new String(rawData); int startIndex = rawAsString.indexOf("41".concat(group)); if (startIndex >= 0) { if (rawData.length < startIndex + 12) { throw new InvalidCommandResponseException("The response was too small"); } String receivedGroup = rawAsString.substring(startIndex + 2, startIndex + 4); if (!receivedGroup.equals(group)) { throw new InvalidCommandResponseException("Unexpected group received: "+receivedGroup); } rawData = rawAsString.substring(startIndex+4, startIndex + 12).getBytes(); } else { throw new InvalidCommandResponseException("The expected status response '41"+ group +"' was not in the response"); } if (rawData.length != 8) { throw new InvalidCommandResponseException("Invalid PIDSupported length: "+rawData.length); } try { List<Integer> pids = new ArrayList<>(8); int groupOffset = Integer.parseInt(this.group, 16); char[] binaries; byte b; /** * the 32 PIDs of the group are encoded bitwise from MSB to LSB (resulting in 8 bytes): * assuming group 00 and the first byte is a 0x0A = (int) 10, * then bits 4 (MSB) and 2 are set, resulting in PIDs 0x01 and 0x03 (counting starts at * PID 0x01, 0x21, ...) are supported */ for (int i = 0; i < rawData.length; i++) { b = rawData[i]; int fromHex = Integer.parseInt(new String(new char[] {'0', (char) b}), 16); BigInteger bigInt = BigInteger.valueOf(fromHex); for (int j = 3; j >= 0; j--) { //check from MSB down to LSB if (bigInt.testBit(j)) { //create an int representation and apply the group offset pids.add(1 + (i*4 + 3-j) + groupOffset); } } } Set<PID> list = new HashSet<>(); /** * conver to hex string so the PIDUtil can parse it */ for (Integer pidInt : pids) { String hex = Integer.toHexString(pidInt); if (hex.length() == 1) { hex = "0".concat(hex); } PID tmp = PIDUtil.fromString(hex); if (tmp != null) { list.add(tmp); } } return list; } catch (RuntimeException e) { throw new InvalidCommandResponseException("The response contained invalid byte values: "+e.getMessage()); } } private byte[] preProcessRawData(byte[] data) { String str = new String(data); if (str.contains("41".concat(this.group))) { int index = str.indexOf("41".concat(this.group)); return Arrays.copyOfRange(data, index, data.length); } return data; } @Override public byte[] getOutputBytes() { return output; } @Override public boolean awaitsResults() { return true; } public String getGroup() { return group; } }