mirror of https://github.com/rusefi/RomRaider.git
DS2 protocol implmentation
This commit is contained in:
parent
b56a0637d1
commit
41b5bc5c9f
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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;
|
||||
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
|
||||
|
||||
|
||||
public interface ProtocolDS2 extends Protocol {
|
||||
|
||||
byte[] constructReadGroupRequest(Module module, byte[][] addresses);
|
||||
|
||||
byte[] constructReadMemoryRequest(
|
||||
Module module, byte[][] convertToByteAddresses, int length);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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;
|
||||
|
||||
|
||||
public final class DS2ChecksumCalculator {
|
||||
|
||||
private DS2ChecksumCalculator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static byte calculateChecksum(byte[] bytes) {
|
||||
byte cs = 0;
|
||||
for (int i = 0; i < (bytes.length - 1); i++) {
|
||||
cs ^= bytes[i];
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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.DS2Protocol.RESPONSE_NON_DATA_BYTES;
|
||||
import static com.romraider.io.protocol.ds2.iso9141.DS2ResponseProcessor.extractResponseData;
|
||||
import static com.romraider.io.protocol.ds2.iso9141.DS2ResponseProcessor.filterRequestFromResponse;
|
||||
import static com.romraider.util.HexUtil.asBytes;
|
||||
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.io.protocol.ProtocolDS2;
|
||||
import com.romraider.logger.ecu.comms.io.protocol.LoggerProtocolDS2;
|
||||
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.definition.EcuData;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
|
||||
public final class DS2LoggerProtocol implements LoggerProtocolDS2 {
|
||||
private final ProtocolDS2 protocol = new DS2Protocol();
|
||||
|
||||
@Override
|
||||
public byte[] constructEcuInitRequest(Module module) {
|
||||
return protocol.constructEcuInitRequest(module);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructEcuResetRequest(Module module) {
|
||||
return protocol.constructEcuResetRequest(module);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressRequest(
|
||||
Module module, Collection<EcuQuery> queries) {
|
||||
|
||||
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
|
||||
return protocol.constructReadAddressRequest(
|
||||
module, convertToByteAddresses(filteredQueries));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadGroupRequest(
|
||||
Module module, String group) {
|
||||
|
||||
return protocol.constructReadGroupRequest(
|
||||
module, new byte[][]{asBytes(group)});
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadMemoryRequest(
|
||||
Module module, Collection<EcuQuery> queries) {
|
||||
|
||||
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
|
||||
return protocol.constructReadMemoryRequest(
|
||||
module, convertToByteAddresses(filteredQueries), getDataLength(filteredQueries));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressResponse(Collection<EcuQuery> queries,
|
||||
PollingState pollState) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadAddressResponse(
|
||||
Collection<EcuQuery> queries, int requestSize) {
|
||||
|
||||
checkNotNullOrEmpty(queries, "queries");
|
||||
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
|
||||
int numAddresses = 0;
|
||||
for (EcuQuery ecuQuery : filteredQueries) {
|
||||
numAddresses += getDataLength(ecuQuery);
|
||||
}
|
||||
return new byte[requestSize + RESPONSE_NON_DATA_BYTES + numAddresses];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructReadGroupResponse(
|
||||
Collection<EcuQuery> queries, int requestSize) {
|
||||
|
||||
checkNotNullOrEmpty(queries, "queries");
|
||||
int size = 0;
|
||||
for (EcuQuery ecuQuery : queries) {
|
||||
size = ((EcuData) ecuQuery.getLoggerData()).getGroupSize();
|
||||
break;
|
||||
}
|
||||
return new byte[requestSize + RESPONSE_NON_DATA_BYTES + size];
|
||||
}
|
||||
|
||||
@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");
|
||||
byte[] responseData = extractResponseData(response);
|
||||
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
|
||||
Map<String, byte[]> addressResults = new HashMap<String, byte[]>();
|
||||
|
||||
for (EcuQuery filteredQuery : filteredQueries) {
|
||||
byte[] bytes = new byte[getDataLength(filteredQuery)];
|
||||
arraycopy(responseData, filteredQuery.getBytes()[0], bytes, 0, bytes.length);
|
||||
addressResults.put(filteredQuery.getHex(), bytes);
|
||||
}
|
||||
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;
|
||||
int addressSize = 0;
|
||||
for (EcuQuery query : queries) {
|
||||
byteCount += query.getAddresses().length;
|
||||
addressSize = query.getBytes().length;
|
||||
}
|
||||
final byte[][] addresses = new byte[byteCount][addressSize];
|
||||
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;
|
||||
}
|
||||
|
||||
private int getDataLength(EcuQuery ecuQuery) {
|
||||
int dataLength = 1;
|
||||
final String dataType =
|
||||
ecuQuery.getLoggerData().getSelectedConvertor().getDataType().toLowerCase();
|
||||
if (dataType.contains("int16")) {
|
||||
dataLength = 2;
|
||||
}
|
||||
else if (dataType.contains("int32") ||
|
||||
dataType.contains("float")) {
|
||||
dataLength = 4;
|
||||
}
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
private int getDataLength(Collection<EcuQuery> queries) {
|
||||
int dataLength = 0;
|
||||
for (EcuQuery query : queries) {
|
||||
final String dataType =
|
||||
query.getLoggerData().getSelectedConvertor().getDataType().toLowerCase();
|
||||
if (dataType.contains("int16")) {
|
||||
dataLength += 2;
|
||||
}
|
||||
else if (dataType.contains("int32") ||
|
||||
dataType.contains("float")) {
|
||||
dataLength += 4;
|
||||
}
|
||||
else {
|
||||
dataLength += 1;
|
||||
}
|
||||
}
|
||||
return dataLength;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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 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.InvalidResponseException;
|
||||
import com.romraider.logger.ecu.exception.UnsupportedProtocolException;
|
||||
|
||||
public final class DS2Protocol implements ProtocolDS2 {
|
||||
public static final byte[] READ_MEMORY_COMMAND = new byte[]{0x06, 0x00};
|
||||
public static final byte[] READ_ADDRESS_COMMAND = new byte[]{0x0B, 0x02, 0x0e};
|
||||
public static final byte[] WRITE_MEMORY_COMMAND = new byte[]{(byte) 0xB0};
|
||||
public static final byte[] WRITE_MEMORY_RESPONSE = new byte[]{(byte) 0xF0};
|
||||
public static final byte[] WRITE_ADDRESS_COMMAND = new byte[]{(byte) 0xB8};
|
||||
public static final byte[] WRITE_ADDRESS_RESPONSE = new byte[]{(byte) 0xF8};
|
||||
public static final byte[] ECU_INIT_COMMAND = new byte[]{0x00};
|
||||
public static final byte VALID_RESPONSE = (byte) 0xA0;
|
||||
public static final int ADDRESS_SIZE = 3;
|
||||
public 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) {
|
||||
|
||||
throw new UnsupportedProtocolException(
|
||||
"Write memory command is not supported on DS2 for address: " +
|
||||
asHex(address));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] constructWriteAddressRequest(
|
||||
Module module, byte[] address, byte value) {
|
||||
|
||||
throw new UnsupportedProtocolException(
|
||||
"Write Address command is not supported on 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) {
|
||||
// 80 10 F0 05 B8 00 00 60 40 DD
|
||||
checkNotNull(module, "module");
|
||||
final byte[] resetAddress = new byte[]{
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x60};
|
||||
final byte reset = 0x40;
|
||||
return constructWriteAddressRequest(module, resetAddress, reset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkValidEcuResetResponse(byte[] processedResponse) {
|
||||
// 80 F0 10 02 F8 40 BA
|
||||
checkNotNullOrEmpty(processedResponse, "processedResponse");
|
||||
DS2ResponseProcessor.validateResponse(processedResponse);
|
||||
byte responseType = processedResponse[4];
|
||||
if (responseType != WRITE_ADDRESS_RESPONSE[0] || processedResponse[5] != (byte) 0x40) {
|
||||
throw new InvalidResponseException("Unexpected " + module.getName() +
|
||||
" Reset response: " + asHex(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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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.io.protocol.ds2.iso9141.DS2Protocol.RESPONSE_NON_DATA_BYTES;
|
||||
import static com.romraider.io.protocol.ds2.iso9141.DS2Protocol.VALID_RESPONSE;
|
||||
import static com.romraider.io.protocol.ds2.iso9141.DS2Protocol.module;
|
||||
import static com.romraider.util.ByteUtil.asByte;
|
||||
import static com.romraider.util.HexUtil.asHex;
|
||||
import static com.romraider.util.ParamChecker.checkNotNull;
|
||||
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
|
||||
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.exception.InvalidResponseException;
|
||||
|
||||
public final class DS2ResponseProcessor {
|
||||
|
||||
private DS2ResponseProcessor() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static byte[] filterRequestFromResponse(byte[] request, byte[] response, PollingState pollState) {
|
||||
checkNotNull(request, "request");
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
checkNotNull(pollState, "pollState");
|
||||
byte[] filteredResponse = new byte[0];
|
||||
if (pollState.getCurrentState() == 0) {
|
||||
filteredResponse = new byte[response.length - request.length];
|
||||
System.arraycopy(response, request.length, filteredResponse, 0, filteredResponse.length);
|
||||
}
|
||||
if (pollState.getCurrentState() == 1) {
|
||||
filteredResponse = new byte[response.length];
|
||||
System.arraycopy(response, 0, filteredResponse, 0, filteredResponse.length);
|
||||
}
|
||||
return filteredResponse;
|
||||
}
|
||||
|
||||
public static void validateResponse(byte[] response) {
|
||||
int i = 0;
|
||||
assertTrue(response.length > RESPONSE_NON_DATA_BYTES, "Invalid response length");
|
||||
assertEquals(module.getAddress()[0], response[i++], "Invalid " + module.getName() + " id");
|
||||
assertEquals(asByte(response.length), response[i++], "Invalid response packet length");
|
||||
assertEquals(VALID_RESPONSE, response[i], "Invalid response");
|
||||
assertEquals(calculateChecksum(response), response[response.length - 1], "Invalid checksum");
|
||||
}
|
||||
|
||||
public static byte[] extractResponseData(byte[] response) {
|
||||
checkNotNullOrEmpty(response, "response");
|
||||
// 12 <length> a0 <bytes> <checksum>
|
||||
validateResponse(response);
|
||||
byte[] data = new byte[response.length - RESPONSE_NON_DATA_BYTES];
|
||||
System.arraycopy(response, (RESPONSE_NON_DATA_BYTES - 1), data, 0, data.length);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
private static void assertTrue(boolean condition, String msg) {
|
||||
if (!condition) {
|
||||
throw new InvalidResponseException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void assertEquals(byte expected, byte actual, String msg) {
|
||||
if (actual != expected) {
|
||||
throw new InvalidResponseException(msg + ". Expected: " + asHex(new byte[]{expected}) + ". Actual: " + asHex(new byte[]{actual}) + ".");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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.logger.ecu.comms.io.connection;
|
||||
|
||||
import static com.romraider.util.HexUtil.asHex;
|
||||
import static com.romraider.util.ParamChecker.checkNotNull;
|
||||
import static org.apache.log4j.Logger.getLogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.romraider.Settings;
|
||||
import com.romraider.io.connection.ConnectionManager;
|
||||
import com.romraider.io.protocol.ProtocolFactory;
|
||||
import com.romraider.logger.ecu.comms.io.protocol.LoggerProtocolDS2;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingState;
|
||||
import com.romraider.logger.ecu.comms.manager.PollingStateImpl;
|
||||
import com.romraider.logger.ecu.comms.query.EcuInitCallback;
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.definition.EcuData;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
import com.romraider.util.SettingsManager;
|
||||
|
||||
public final class DS2LoggerConnection implements LoggerConnection {
|
||||
private static final Logger LOGGER = getLogger(DS2LoggerConnection.class);
|
||||
private final LoggerProtocolDS2 protocol;
|
||||
private final ConnectionManager manager;
|
||||
Settings settings = SettingsManager.getSettings();
|
||||
|
||||
public DS2LoggerConnection(ConnectionManager manager) {
|
||||
checkNotNull(manager, "manager");
|
||||
this.manager = manager;
|
||||
|
||||
this.protocol = (LoggerProtocolDS2) ProtocolFactory.getProtocol(
|
||||
settings.getLoggerProtocol(),
|
||||
settings.getTransportProtocol());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ecuReset(Module module) {
|
||||
byte[] request = protocol.constructEcuResetRequest(module);
|
||||
LOGGER.debug("ECU Reset Request ---> " + asHex(request));
|
||||
byte[] response = manager.send(request);
|
||||
byte[] processedResponse = protocol.preprocessResponse(request, response, new PollingStateImpl());
|
||||
LOGGER.debug("ECU Reset Response <--- " + asHex(processedResponse));
|
||||
protocol.processEcuResetResponse(processedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ecuInit(EcuInitCallback callback, Module module) {
|
||||
byte[] request = protocol.constructEcuInitRequest(module);
|
||||
LOGGER.debug("ECU Init Request ---> " + asHex(request));
|
||||
byte[] response = manager.send(request);
|
||||
LOGGER.trace("ECU Init Raw Response <--- " + asHex(response));
|
||||
byte[] processedResponse = protocol.preprocessResponse(request, response, new PollingStateImpl());
|
||||
LOGGER.debug("ECU Init Response <--- " + asHex(processedResponse));
|
||||
protocol.processEcuInitResponse(callback, processedResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void sendAddressReads(
|
||||
Collection<EcuQuery> queries,
|
||||
Module module,
|
||||
PollingState pollState) {
|
||||
|
||||
final Map<String, Collection<EcuQuery>> groupList = getGroupList(queries);
|
||||
for (String group : groupList.keySet().toArray(new String[0])) {
|
||||
final Collection<EcuQuery> querySet = groupList.get(group);
|
||||
byte[] request = new byte[0];
|
||||
byte[] response = new byte[0];
|
||||
if (group.equalsIgnoreCase("0x0b0x020e")) {
|
||||
for (EcuQuery query : querySet) {
|
||||
final Collection<EcuQuery> queryList = new ArrayList<EcuQuery>();
|
||||
queryList.add(query);
|
||||
request = protocol.constructReadAddressRequest(
|
||||
module, queryList);
|
||||
LOGGER.debug("Mode:" + pollState.getCurrentState() +
|
||||
" ECU Request ---> " + asHex(request));
|
||||
response = protocol.constructReadAddressResponse(
|
||||
queryList, request.length);
|
||||
protocol.processReadAddressResponses(
|
||||
queryList,
|
||||
sendRcv(request, response, pollState),
|
||||
pollState);
|
||||
}
|
||||
}
|
||||
else if (group.equalsIgnoreCase("0x060x00")) {
|
||||
for (EcuQuery query : querySet) {
|
||||
final Collection<EcuQuery> queryList = new ArrayList<EcuQuery>();
|
||||
queryList.add(query);
|
||||
request = protocol.constructReadMemoryRequest(
|
||||
module, queryList);
|
||||
LOGGER.debug("Mode:" + pollState.getCurrentState() +
|
||||
" ECU Request ---> " + asHex(request));
|
||||
response = protocol.constructReadAddressResponse(
|
||||
queryList, request.length);
|
||||
protocol.processReadAddressResponses(
|
||||
queryList,
|
||||
sendRcv(request, response, pollState),
|
||||
pollState);
|
||||
}
|
||||
}
|
||||
else {
|
||||
request = protocol.constructReadGroupRequest(
|
||||
module, group);
|
||||
LOGGER.debug("Mode:" + pollState.getCurrentState() +
|
||||
" ECU Request ---> " + asHex(request));
|
||||
response = protocol.constructReadGroupResponse(
|
||||
querySet, request.length);
|
||||
protocol.processReadAddressResponses(
|
||||
querySet,
|
||||
sendRcv(request, response, pollState),
|
||||
pollState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearLine() {
|
||||
manager.clearLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
manager.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void sendAddressWrites(
|
||||
Map<EcuQuery, byte[]> writeQueries, Module module) {
|
||||
|
||||
for (EcuQuery writeKey : writeQueries.keySet()) {
|
||||
if (writeKey.getBytes().length == 3) {
|
||||
final byte[] request =
|
||||
protocol.constructWriteAddressRequest(
|
||||
module,
|
||||
writeKey.getBytes(),
|
||||
writeQueries.get(writeKey)[0]);
|
||||
|
||||
LOGGER.debug("ECU Write Request ---> " + asHex(request));
|
||||
final byte[] response = manager.send(request);
|
||||
byte[] processedResponse =
|
||||
protocol.preprocessResponse(
|
||||
request,
|
||||
response,
|
||||
new PollingStateImpl());
|
||||
LOGGER.debug("ECU Write Response <--- " + asHex(processedResponse));
|
||||
protocol.processWriteResponse(
|
||||
writeQueries.get(writeKey), processedResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a map of groups each with a value of a list of queries having the same group
|
||||
private Map<String, Collection<EcuQuery>> getGroupList(Collection<EcuQuery> queries) {
|
||||
final Map<String, Collection<EcuQuery>> groups = new HashMap<String, Collection<EcuQuery>>();
|
||||
String group;
|
||||
String subGroup;
|
||||
for (EcuQuery query : queries) {
|
||||
group = ((EcuData) query.getLoggerData()).getGroup();
|
||||
subGroup = ((EcuData) query.getLoggerData()).getSubgroup();
|
||||
group = group + (subGroup == null ? "" : subGroup);
|
||||
if (!groups.containsKey(group)) {
|
||||
final Collection<EcuQuery> queryList = new ArrayList<EcuQuery>();
|
||||
queryList.add(query);
|
||||
groups.put(group, queryList);
|
||||
}
|
||||
else {
|
||||
groups.get(group).add(query);
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
private byte[] sendRcv(byte[] request, byte[] response, PollingState pollState) {
|
||||
manager.send(request, response, pollState);
|
||||
LOGGER.trace("ECU Read Raw Response <--- " + asHex(response));
|
||||
final byte[] processedResponse = protocol.preprocessResponse(
|
||||
request, response, pollState);
|
||||
LOGGER.debug("Mode:" + pollState.getCurrentState() +
|
||||
" ECU Response <--- " + asHex(processedResponse));
|
||||
return processedResponse;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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.logger.ecu.comms.io.protocol;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.romraider.logger.ecu.comms.query.EcuQuery;
|
||||
import com.romraider.logger.ecu.definition.Module;
|
||||
|
||||
|
||||
|
||||
public interface LoggerProtocolDS2 extends LoggerProtocol {
|
||||
|
||||
byte[] constructReadGroupRequest(
|
||||
Module module, String group);
|
||||
|
||||
byte[] constructReadGroupResponse(
|
||||
Collection<EcuQuery> queries, int requestSize);
|
||||
|
||||
byte[] constructReadAddressResponse(
|
||||
Collection<EcuQuery> queries, int requestSize);
|
||||
|
||||
byte[] constructReadMemoryRequest(
|
||||
Module module, Collection<EcuQuery> queryList);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2014 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.logger.ecu.comms.query;
|
||||
|
||||
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
|
||||
import static java.lang.System.arraycopy;
|
||||
|
||||
public final class DS2EcuInit implements EcuInit {
|
||||
private byte[] ecuInitBytes;
|
||||
private String ecuId;
|
||||
|
||||
public DS2EcuInit(byte[] ecuInitBytes) {
|
||||
checkNotNullOrEmpty(ecuInitBytes, "ecuInitBytes");
|
||||
this.ecuInitBytes = ecuInitBytes;
|
||||
final byte[] ecuIdBytes = new byte[7];
|
||||
arraycopy(ecuInitBytes, 0, ecuIdBytes, 0, 7);
|
||||
ecuId = new String(ecuIdBytes);
|
||||
}
|
||||
|
||||
public String getEcuId() {
|
||||
return ecuId;
|
||||
}
|
||||
|
||||
public byte[] getEcuInitBytes() {
|
||||
return ecuInitBytes;
|
||||
}
|
||||
|
||||
}
|
|
@ -22,9 +22,9 @@ version.major=0
|
|||
version.minor=5
|
||||
version.patch=8
|
||||
version.buildnumber=635
|
||||
version.extra=RC
|
||||
version.extra=DS2
|
||||
version.extra1=1
|
||||
min.logger.def.version=155
|
||||
min.logger.def.version=291
|
||||
|
||||
# the starting class for the application
|
||||
class.start=com.romraider.ECUExec
|
||||
|
|
Loading…
Reference in New Issue