/* * RomRaider Open-Source Tuning, Logging and Reflashing * Copyright (C) 2006-2015 RomRaider.com * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package com.romraider.io.protocol.obd.iso15765; import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.RESPONSE_NON_DATA_BYTES; import static com.romraider.io.protocol.obd.iso15765.OBDResponseProcessor.extractResponseData; import static com.romraider.io.protocol.obd.iso15765.OBDResponseProcessor.filterRequestFromResponse; import static com.romraider.util.HexUtil.asHex; import static com.romraider.util.ParamChecker.checkNotNull; import static com.romraider.util.ParamChecker.checkNotNullOrEmpty; import static java.lang.System.arraycopy; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.romraider.io.protocol.Protocol; import com.romraider.logger.ecu.comms.io.protocol.LoggerProtocolOBD; import com.romraider.logger.ecu.comms.manager.PollingState; import com.romraider.logger.ecu.comms.query.EcuInit; import com.romraider.logger.ecu.comms.query.EcuInitCallback; import com.romraider.logger.ecu.comms.query.EcuQuery; import com.romraider.logger.ecu.comms.query.EcuQueryData; import com.romraider.logger.ecu.definition.Module; public final class OBDLoggerProtocol implements LoggerProtocolOBD { private final Protocol protocol = new OBDProtocol(); @Override public byte[] constructEcuInitRequest(Module module) { return protocol.constructEcuInitRequest(module); } @Override public byte[] constructEcuResetRequest(Module module, int resetCode) { return protocol.constructEcuResetRequest(module, resetCode); } @Override public byte[] constructReadAddressRequest( Module module, Collection<EcuQuery> queries) { Collection<EcuQuery> filteredQueries = filterDuplicates(queries); return protocol.constructReadAddressRequest( module, convertToByteAddresses(filteredQueries)); } @Override public byte[] constructReadPidRequest(Module module, byte[] pid) { final byte[][] request = new byte[1][pid.length]; arraycopy(pid, 0, request[0], 0, pid.length); return protocol.constructReadAddressRequest(module, request); } @Override public byte[] constructReadAddressResponse( Collection<EcuQuery> queries, PollingState pollState) { checkNotNullOrEmpty(queries, "queries"); // four byte - CAN ID // one byte - Response mode // one byte - Response pid // variable bytes of data defined for pid Collection<EcuQuery> filteredQueries = filterDuplicates(queries); int numAddresses = 0; for (EcuQuery ecuQuery : filteredQueries) { numAddresses += ecuQuery.getBytes().length; numAddresses += EcuQueryData.getDataLength(ecuQuery); } return new byte[(numAddresses + RESPONSE_NON_DATA_BYTES)]; } @Override public byte[] preprocessResponse( byte[] request, byte[] response, PollingState pollState) { return filterRequestFromResponse(request, response, pollState); } @Override public void processEcuInitResponse(EcuInitCallback callback, byte[] response) { checkNotNull(callback, "callback"); checkNotNullOrEmpty(response, "response"); protocol.checkValidEcuInitResponse(response); EcuInit ecuInit = protocol.parseEcuInitResponse(response); callback.callback(ecuInit); } @Override public void processEcuResetResponse(byte[] response) { checkNotNullOrEmpty(response, "response"); protocol.checkValidEcuResetResponse(response); } // processes the response bytes and sets individual responses on corresponding query objects @Override public void processReadAddressResponses( Collection<EcuQuery> queries, byte[] response, PollingState pollState) { checkNotNullOrEmpty(queries, "queries"); checkNotNullOrEmpty(response, "response"); final byte[] responseData = extractResponseData(response); final Collection<EcuQuery> filteredQueries = filterDuplicates(queries); final Map<String, byte[]> addressResults = new HashMap<String, byte[]>(); int i = 0; for (EcuQuery filteredQuery : filteredQueries) { final int addrLength = filteredQuery.getBytes().length; final int dataLength = EcuQueryData.getDataLength(filteredQuery); final byte[] addr = new byte[addrLength]; final byte[] data = new byte[dataLength]; arraycopy(responseData, i, addr, 0, addrLength); arraycopy(responseData, i + addrLength, data, 0, dataLength); addressResults.put(asHex(addr), data); i += addrLength + dataLength; } for (EcuQuery query : queries) { query.setResponse(addressResults.get(query.getHex())); } } @Override public Protocol getProtocol() { return protocol; } @Override public byte[] constructWriteAddressRequest( Module module, byte[] writeAddress, byte value) { return protocol.constructWriteAddressRequest(module, writeAddress, value); } @Override public void processWriteResponse(byte[] data, byte[] response) { checkNotNullOrEmpty(data, "data"); checkNotNullOrEmpty(response, "response"); protocol.checkValidWriteResponse(data, response); } private Collection<EcuQuery> filterDuplicates(Collection<EcuQuery> queries) { Collection<EcuQuery> filteredQueries = new ArrayList<EcuQuery>(); for (EcuQuery query : queries) { if (!filteredQueries.contains(query)) { filteredQueries.add(query); } } return filteredQueries; } private byte[][] convertToByteAddresses(Collection<EcuQuery> queries) { int byteCount = 0; for (EcuQuery query : queries) { byteCount += query.getAddresses().length; } final int ADDRESS_SIZE = 1; // TODO how do we handle variable address lengths ? final byte[][] addresses = new byte[byteCount][ADDRESS_SIZE]; int i = 0; for (EcuQuery query : queries) { final int addrLength = query.getBytes().length; final byte[] bytes = query.getBytes(); for (int j = 0; j < bytes.length / addrLength; j++) { arraycopy(bytes, j * addrLength, addresses[i++], 0, addrLength); } } return addresses; } }