package org.envirocar.obd.commands.response; import org.envirocar.core.logging.Logger; import org.envirocar.obd.commands.PID; import org.envirocar.obd.commands.PIDUtil; import org.envirocar.obd.commands.response.entity.EngineLoadResponse; import org.envirocar.obd.commands.response.entity.EngineRPMResponse; import org.envirocar.obd.commands.response.entity.FuelPressureResponse; import org.envirocar.obd.commands.response.entity.GenericDataResponse; import org.envirocar.obd.commands.response.entity.IntakeAirTemperatureResponse; import org.envirocar.obd.commands.response.entity.IntakeManifoldAbsolutePressureResponse; import org.envirocar.obd.commands.response.entity.LambdaProbeCurrentResponse; import org.envirocar.obd.commands.response.entity.LambdaProbeVoltageResponse; import org.envirocar.obd.commands.response.entity.LongTermFuelTrimResponse; import org.envirocar.obd.commands.response.entity.MAFResponse; import org.envirocar.obd.commands.response.entity.ShortTermFuelTrimResponse; import org.envirocar.obd.commands.response.entity.SpeedResponse; import org.envirocar.obd.commands.response.entity.ThrottlePositionResponse; import org.envirocar.obd.exception.AdapterSearchingException; import org.envirocar.obd.exception.InvalidCommandResponseException; import org.envirocar.obd.exception.NoDataReceivedException; import org.envirocar.obd.exception.UnmatchedResponseException; public class ResponseParser { private static final Logger LOGGER = Logger.getLogger(ResponseParser.class); private static final CharSequence SEARCHING = "SEARCHING"; private static final CharSequence STOPPED = "STOPPED"; private static final CharSequence NO_DATA = "NODATA"; public static final String STATUS_OK = "41"; public ResponseParser() { } public DataResponse parse(byte[] data) throws AdapterSearchingException, NoDataReceivedException, InvalidCommandResponseException, UnmatchedResponseException { /** * we received a char array as hexadecimal --> * two chars represent one byte */ int index = 0; int length = 2; String dataString = new String(data); //cartrend: 7E803410D00AAAAAAAA //= 410D00AAAAAAAA // if (dataString.startsWith("7E803")) { // dataString = dataString.substring(5, dataString.length()); // } if (isSearching(dataString)) { throw new AdapterSearchingException(); } else if (isNoDataCommand(dataString)) { throw new NoDataReceivedException("NODATA was received"); } int[] buffer = new int[data.length / 2]; boolean error = false; PID pid = null; while (index + length <= data.length) { String tmp = new String(data, index, length); // this is the status if (index == 0) { if (!tmp.equals(STATUS_OK)) { error = true; } } // this is the ID byte else if (index == 2) { pid = PIDUtil.fromString(tmp); if (error || pid == null) { throw new InvalidCommandResponseException(pid == null ? tmp : pid.toString()); } } else { /* * this is a hex number */ buffer[index/2] = Integer.parseInt(tmp, 16); if (buffer[index/2] < 0) { throw new InvalidCommandResponseException(pid.toString()); } } index += length; } return createDataResponse(pid, buffer, data); } private DataResponse createDataResponse(PID pid, int[] processedData, byte[] rawData) throws InvalidCommandResponseException, UnmatchedResponseException { switch (pid) { // case FUEL_SYSTEM_STATUS: // return FuelSystemStatusResponse.fromRawData(rawData); case CALCULATED_ENGINE_LOAD: return new EngineLoadResponse((processedData[2] * 100.0f) / 255.0f); case FUEL_PRESSURE: return new FuelPressureResponse(processedData[2] * 3); case INTAKE_MAP: return new IntakeManifoldAbsolutePressureResponse(processedData[2]); case RPM: return new EngineRPMResponse((processedData[2] * 256 + processedData[3]) / 4); case SPEED: return new SpeedResponse(processedData[2]); case INTAKE_AIR_TEMP: return new IntakeAirTemperatureResponse(processedData[2] - 40); case MAF: return new MAFResponse((processedData[2] * 256 + processedData[3]) / 100.0f); case TPS: return new ThrottlePositionResponse((processedData[2] * 100) / 255); case SHORT_TERM_FUEL_TRIM_BANK_1: return new ShortTermFuelTrimResponse((processedData[2] - 128) * (100d / 128d), 1); case LONG_TERM_FUEL_TRIM_BANK_1: return new LongTermFuelTrimResponse((processedData[2] - 128) * (100d / 128d), 1); case O2_LAMBDA_PROBE_1_VOLTAGE: case O2_LAMBDA_PROBE_2_VOLTAGE: case O2_LAMBDA_PROBE_3_VOLTAGE: case O2_LAMBDA_PROBE_4_VOLTAGE: case O2_LAMBDA_PROBE_5_VOLTAGE: case O2_LAMBDA_PROBE_6_VOLTAGE: case O2_LAMBDA_PROBE_7_VOLTAGE: case O2_LAMBDA_PROBE_8_VOLTAGE: LambdaProbeVoltageResponse lambda = new LambdaProbeVoltageResponse( ((processedData[4] * 256d) + processedData[5]) / 8192d, ((processedData[2] * 256d) + processedData[3]) / 32768d); return lambda; case O2_LAMBDA_PROBE_1_CURRENT: case O2_LAMBDA_PROBE_2_CURRENT: case O2_LAMBDA_PROBE_3_CURRENT: case O2_LAMBDA_PROBE_4_CURRENT: case O2_LAMBDA_PROBE_5_CURRENT: case O2_LAMBDA_PROBE_6_CURRENT: case O2_LAMBDA_PROBE_7_CURRENT: case O2_LAMBDA_PROBE_8_CURRENT: return new LambdaProbeCurrentResponse( ((processedData[4]*256d) + processedData[5])/256d - 128, ((processedData[2]*256d) + processedData[3]) / 32768d); } return new GenericDataResponse(pid, processedData, rawData); } private boolean isSearching(String dataString) { return dataString.contains(SEARCHING) || dataString.contains(STOPPED); } private boolean isNoDataCommand(String dataString) { return dataString == null || dataString.contains(NO_DATA); } }