diff --git a/src/main/java/com/romraider/io/protocol/ProtocolDS2.java b/src/main/java/com/romraider/io/protocol/ProtocolDS2.java new file mode 100644 index 00000000..135d1cd8 --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/ProtocolDS2.java @@ -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); +} diff --git a/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2ChecksumCalculator.java b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2ChecksumCalculator.java new file mode 100644 index 00000000..6d011910 --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2ChecksumCalculator.java @@ -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; + } +} diff --git a/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2LoggerProtocol.java b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2LoggerProtocol.java new file mode 100644 index 00000000..816aa70a --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2LoggerProtocol.java @@ -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 queries) { + + Collection 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 queries) { + + Collection filteredQueries = filterDuplicates(queries); + return protocol.constructReadMemoryRequest( + module, convertToByteAddresses(filteredQueries), getDataLength(filteredQueries)); + } + + @Override + public byte[] constructReadAddressResponse(Collection queries, + PollingState pollState) { + return null; + } + + @Override + public byte[] constructReadAddressResponse( + Collection queries, int requestSize) { + + checkNotNullOrEmpty(queries, "queries"); + Collection 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 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 queries, byte[] response, PollingState pollState) { + checkNotNullOrEmpty(queries, "queries"); + checkNotNullOrEmpty(response, "response"); + byte[] responseData = extractResponseData(response); + Collection filteredQueries = filterDuplicates(queries); + Map addressResults = new HashMap(); + + 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 filterDuplicates(Collection queries) { + Collection filteredQueries = new ArrayList(); + for (EcuQuery query : queries) { + if (!filteredQueries.contains(query)) { + filteredQueries.add(query); + } + } + return filteredQueries; + } + + private byte[][] convertToByteAddresses(Collection 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 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; + } +} diff --git a/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2Protocol.java b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2Protocol.java new file mode 100644 index 00000000..dfff0415 --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2Protocol.java @@ -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 + 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; + } +} diff --git a/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2ResponseProcessor.java b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2ResponseProcessor.java new file mode 100644 index 00000000..5baab09b --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/ds2/iso9141/DS2ResponseProcessor.java @@ -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 a0 + 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}) + "."); + } + } +} diff --git a/src/main/java/com/romraider/logger/ecu/comms/io/connection/DS2LoggerConnection.java b/src/main/java/com/romraider/logger/ecu/comms/io/connection/DS2LoggerConnection.java new file mode 100644 index 00000000..0d0850e2 --- /dev/null +++ b/src/main/java/com/romraider/logger/ecu/comms/io/connection/DS2LoggerConnection.java @@ -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 queries, + Module module, + PollingState pollState) { + + final Map> groupList = getGroupList(queries); + for (String group : groupList.keySet().toArray(new String[0])) { + final Collection querySet = groupList.get(group); + byte[] request = new byte[0]; + byte[] response = new byte[0]; + if (group.equalsIgnoreCase("0x0b0x020e")) { + for (EcuQuery query : querySet) { + final Collection queryList = new ArrayList(); + 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 queryList = new ArrayList(); + 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 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> getGroupList(Collection queries) { + final Map> groups = new HashMap>(); + 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 queryList = new ArrayList(); + 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; + } +} diff --git a/src/main/java/com/romraider/logger/ecu/comms/io/protocol/LoggerProtocolDS2.java b/src/main/java/com/romraider/logger/ecu/comms/io/protocol/LoggerProtocolDS2.java new file mode 100644 index 00000000..5effcb97 --- /dev/null +++ b/src/main/java/com/romraider/logger/ecu/comms/io/protocol/LoggerProtocolDS2.java @@ -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 queries, int requestSize); + + byte[] constructReadAddressResponse( + Collection queries, int requestSize); + + byte[] constructReadMemoryRequest( + Module module, Collection queryList); +} diff --git a/src/main/java/com/romraider/logger/ecu/comms/query/DS2EcuInit.java b/src/main/java/com/romraider/logger/ecu/comms/query/DS2EcuInit.java new file mode 100644 index 00000000..66a01a90 --- /dev/null +++ b/src/main/java/com/romraider/logger/ecu/comms/query/DS2EcuInit.java @@ -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; + } + +} diff --git a/version.properties b/version.properties index ee4c5ce4..bbe8fdcc 100644 --- a/version.properties +++ b/version.properties @@ -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