/* * 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.ds2.iso9141; import static com.romraider.io.protocol.ds2.iso9141.DS2ChecksumCalculator.calculateChecksum; import static com.romraider.util.ByteUtil.asByte; import static com.romraider.util.HexUtil.asHex; import static com.romraider.util.ParamChecker.checkGreaterThanZero; import static com.romraider.util.ParamChecker.checkNotNull; import static com.romraider.util.ParamChecker.checkNotNullOrEmpty; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import com.romraider.io.connection.ConnectionProperties; import com.romraider.io.protocol.ProtocolDS2; import com.romraider.logger.ecu.comms.manager.PollingState; import com.romraider.logger.ecu.comms.query.DS2EcuInit; import com.romraider.logger.ecu.comms.query.EcuInit; import com.romraider.logger.ecu.definition.Module; import com.romraider.logger.ecu.exception.UnsupportedProtocolException; public final class DS2Protocol implements ProtocolDS2 { private static final byte[] READ_MEMORY_COMMAND = new byte[]{0x06, 0x00}; private static final byte[] READ_ADDRESS_COMMAND = new byte[]{0x0B, 0x02, 0x0e}; private static final byte[] ECU_INIT_COMMAND = new byte[]{0x00}; private static final byte[] ECU_RESET_COMMAND = new byte[]{0x43}; public static final byte VALID_RESPONSE = (byte) 0xA0; private static final int ADDRESS_SIZE = 3; private static final int DATA_SIZE = 1; public static final int RESPONSE_NON_DATA_BYTES = 4; public static Module module; private final ByteArrayOutputStream bb = new ByteArrayOutputStream(255); @Override public byte[] constructEcuInitRequest(Module module) { checkNotNull(module, "module"); DS2Protocol.module = module; // 0x12 0x04 0x00 0x16 return buildRequest(ECU_INIT_COMMAND, new byte[0], new byte[0]); } @Override public byte[] constructWriteMemoryRequest( Module module, byte[] address, byte[] values) { return buildRequest(new byte[0], new byte[0], values); } @Override public byte[] constructWriteAddressRequest( Module module, byte[] address, byte value) { throw new UnsupportedProtocolException( "Write Address command is not supported by DS2 for address: " + asHex(address)); } @Override public byte[] constructReadMemoryRequest( Module module, byte[] address, int numBytes) { return constructReadMemoryRequest( module, new byte[][]{address}, numBytes); } @Override public byte[] constructReadMemoryRequest( Module module, byte[][] address, int numBytes) { checkNotNull(module, "module"); checkNotNullOrEmpty(address, "address"); checkGreaterThanZero(numBytes, "numBytes"); // 0x12 0x09 0x06 <seg> <from_address> <num_bytes> return buildRequest( READ_MEMORY_COMMAND, new byte[]{asByte(numBytes)}, address); } @Override public byte[] constructReadAddressRequest( Module module, byte[][] addresses) { checkNotNull(module, "module"); checkNotNullOrEmpty(addresses, "addresses"); // 0x12 data_length group subgroup [address] checksum return buildRequest(READ_ADDRESS_COMMAND, new byte[0], addresses); } public byte[] constructReadGroupRequest( Module module, byte[][] addresses) { checkNotNull(module, "module"); checkNotNullOrEmpty(addresses, "addresses"); // 0x12 data_length group subgroup checksum return buildRequest(new byte[0], new byte[0], addresses); } @Override public byte[] preprocessResponse(byte[] request, byte[] response, PollingState pollState) { return DS2ResponseProcessor.filterRequestFromResponse(request, response, pollState); } @Override public byte[] parseResponseData(byte[] processedResponse) { checkNotNullOrEmpty(processedResponse, "processedResponse"); return DS2ResponseProcessor.extractResponseData(processedResponse); } @Override public void checkValidEcuInitResponse(byte[] processedResponse) { // 12 2e a0 31343337383036 3131303133303231323239363030303031313538353236303030393632313432353634 9c checkNotNullOrEmpty(processedResponse, "processedResponse"); DS2ResponseProcessor.validateResponse(processedResponse); } @Override public EcuInit parseEcuInitResponse(byte[] processedResponse) { return new DS2EcuInit(parseResponseData(processedResponse)); } @Override public final byte[] constructEcuResetRequest(Module module, int resetCode) { // 0x12 data_length cmd byte1 byte2 checksum checkNotNull(module, "module"); final byte[] resetBytes = ByteBuffer.allocate(4).putInt(resetCode).array(); final byte[] reset = new byte[2]; System.arraycopy(resetBytes, 2, reset, 0, 2); return buildRequest(ECU_RESET_COMMAND, new byte[0], reset); } @Override public void checkValidEcuResetResponse(byte[] processedResponse) { // 80 F0 10 02 F8 40 BA checkNotNullOrEmpty(processedResponse, "processedResponse"); DS2ResponseProcessor.validateResponse(processedResponse); } @Override public void checkValidWriteResponse(byte[] data, byte[] processedResponse) { } @Override public ConnectionProperties getDefaultConnectionProperties() { return new ConnectionProperties() { public int getBaudRate() { return 9600; } public void setBaudRate(int b) { } public int getDataBits() { return 8; } public int getStopBits() { return 1; } public int getParity() { return 2; } public int getConnectTimeout() { return 2000; } public int getSendTimeout() { return 55; } }; } private final byte[] buildRequest( byte[] command, byte[] readLen, byte[]... content) { byte[] request = new byte[0]; try { int length = 3; for (byte[] tmp : content) { length += tmp.length; } length += command.length; length += readLen.length; bb.reset(); bb.write(module.getAddress()); bb.write((byte) length); bb.write(command); for (byte[] tmp : content) { bb.write(tmp); } if (readLen.length > 0) { bb.write(readLen); } bb.write((byte) 0x00); request = bb.toByteArray(); final byte cs = calculateChecksum(request); request[request.length - 1] = cs; } catch (IOException e) { e.printStackTrace(); } return request; } }