Implement DS2 "Telegram" logging mode

This commit is contained in:
Dale Schultz 2020-05-18 20:25:47 -04:00
parent 0373b15a4f
commit b66ba92692
No known key found for this signature in database
GPG Key ID: EA2C8AD6CB5C2AF2
6 changed files with 260 additions and 45 deletions

View File

@ -0,0 +1 @@
TOOLARGE = Parameter request too large (maximum 32), un-select some parameters

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2014 RomRaider.com
* Copyright (C) 2006-2020 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
@ -21,12 +21,17 @@ package com.romraider.io.protocol;
import com.romraider.logger.ecu.definition.Module;
public interface ProtocolDS2 extends Protocol {
byte[] constructReadProcedureRequest(Module module, byte[][] addresses);
byte[] constructReadGroupRequest(Module module, byte[][] addresses);
byte[] constructReadMemoryRequest(
Module module, byte[][] convertToByteAddresses, int length);
byte[] constructSetAddressRequest(
Module module, byte[][] convertToByteAddresses);
void validateSetAddressResponse(byte[] response);
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2020 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
@ -22,6 +22,7 @@ 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.ByteUtil.asUnsignedInt;
import static com.romraider.util.HexUtil.asBytes;
import static com.romraider.util.ParamChecker.checkNotNull;
import static com.romraider.util.ParamChecker.checkNotNullOrEmpty;
@ -60,8 +61,16 @@ public final class DS2LoggerProtocol implements LoggerProtocolDS2 {
public byte[] constructReadAddressRequest(
Module module, Collection<EcuQuery> queries) {
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
return protocol.constructReadAddressRequest(
module, new byte[][]{});
}
@Override
public byte[] constructReadProcedureRequest(
Module module, Collection<EcuQuery> queries) {
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
return protocol.constructReadProcedureRequest(
module, convertToByteAddresses(filteredQueries));
}
@ -90,6 +99,26 @@ public final class DS2LoggerProtocol implements LoggerProtocolDS2 {
module, convertToByteAddresses(queries), length);
}
/**
* Convert address for the list of queries into the hex format the
* ECU expects.
**/
@Override
public byte[] constructSetAddressRequest(Module module,
Collection<EcuQuery> queries) {
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
return protocol.constructSetAddressRequest(
module, convertListToByteAddresses(filteredQueries));
}
/**
* An Address set response is a 4 byte ACK sequence
**/
@Override
public byte[] constructSetAddressResponse(int requestSize) {
return new byte[requestSize + RESPONSE_NON_DATA_BYTES];
}
@Override
public byte[] constructReadAddressResponse(Collection<EcuQuery> queries,
PollingState pollState) {
@ -102,11 +131,11 @@ public final class DS2LoggerProtocol implements LoggerProtocolDS2 {
checkNotNullOrEmpty(queries, "queries");
Collection<EcuQuery> filteredQueries = filterDuplicates(queries);
int numAddresses = 0;
int responseBytes = requestSize + RESPONSE_NON_DATA_BYTES;
for (EcuQuery ecuQuery : filteredQueries) {
numAddresses += EcuQueryData.getDataLength(ecuQuery);
responseBytes += EcuQueryData.getDataLength(ecuQuery);
}
return new byte[requestSize + RESPONSE_NON_DATA_BYTES + numAddresses];
return new byte[responseBytes];
}
@Override
@ -156,7 +185,7 @@ public final class DS2LoggerProtocol implements LoggerProtocolDS2 {
* array.
**/
@Override
public void processReadAddressResponses(Collection<EcuQuery> queries, byte[] response, PollingState pollState) {
public void processReadAddressResponse(Collection<EcuQuery> queries, byte[] response, PollingState pollState) {
checkNotNullOrEmpty(queries, "queries");
checkNotNullOrEmpty(response, "response");
byte[] responseData = extractResponseData(response);
@ -215,6 +244,36 @@ public final class DS2LoggerProtocol implements LoggerProtocolDS2 {
}
}
@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 dataLength = EcuQueryData.getDataLength(filteredQuery);
final byte[] data = new byte[dataLength];
arraycopy(responseData, i, data, 0, dataLength);
addressResults.put(filteredQuery.getHex(), data);
i += dataLength;
}
for (EcuQuery query : queries) {
query.setResponse(addressResults.get(query.getHex()));
}
}
/**
* Validate response headers, length and checksum
**/
@Override
public void validateSetAddressResponse(byte[] response) {
checkNotNullOrEmpty(response, "response");
protocol.validateSetAddressResponse(response);
}
@Override
public Protocol getProtocol() {
return protocol;
@ -263,6 +322,34 @@ public final class DS2LoggerProtocol implements LoggerProtocolDS2 {
return addresses;
}
private byte[][] convertListToByteAddresses(Collection<EcuQuery> queries) {
/*
* Address format is five bytes. First byte is data type
* (byte, word, procedure) followed by the four byte address.
*/
final byte[][] addresses = new byte[queries.size()][5];
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], 1, addrLength);
}
// Update the first byte to the appropriate data type
// 0 = byte, 1 = word and 2 = procedure
// procedure
if (asUnsignedInt(bytes) < 0x1C) {
addresses[i][0] = 2;
}
// word or byte
else {
addresses[i][0] = (byte) (EcuQueryData.getDataLength(query) - 1);
}
i++;
}
return addresses;
}
private int getDataLength(Collection<EcuQuery> queries) {
int dataLength = 0;
for (EcuQuery query : queries) {

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2020 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
@ -40,12 +40,12 @@ 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[] READ_PROCEDURE_COMMAND = new byte[]{0x0B, 0x02};
private static final byte[] ECU_INIT_COMMAND = new byte[]{0x00};
private static final byte[] ECU_RESET_COMMAND = new byte[]{0x43};
private static final byte[] SET_ADDRESS_COMMAND = new byte[]{0x0B, 0x01};
private static final byte[] READ_ADDRESS_COMMAND = new byte[]{0x0B, 0x00};
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);
@ -97,9 +97,18 @@ public final class DS2Protocol implements ProtocolDS2 {
public byte[] constructReadAddressRequest(
Module module, byte[][] addresses) {
checkNotNull(module, "module");
// 0x12 0x05 0x0B 0x00
return buildRequest(
READ_ADDRESS_COMMAND, new byte[0], new byte[]{0});
}
@Override
public byte[] constructReadProcedureRequest(
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);
// 0x12 data_length group subgroup [procedure] checksum
return buildRequest(READ_PROCEDURE_COMMAND, new byte[0], addresses);
}
public byte[] constructReadGroupRequest(
@ -110,6 +119,14 @@ public final class DS2Protocol implements ProtocolDS2 {
return buildRequest(new byte[0], new byte[0], addresses);
}
@Override
public byte[] constructSetAddressRequest(Module module,
byte[][] addresses) {
checkNotNull(module, "module");
checkNotNullOrEmpty(addresses, "address");
return buildRequest(SET_ADDRESS_COMMAND, new byte[0], addresses);
}
@Override
public byte[] preprocessResponse(byte[] request, byte[] response, PollingState pollState) {
return DS2ResponseProcessor.filterRequestFromResponse(request, response, pollState);
@ -128,6 +145,13 @@ public final class DS2Protocol implements ProtocolDS2 {
DS2ResponseProcessor.validateResponse(processedResponse);
}
@Override
public void validateSetAddressResponse(byte[] processedResponse) {
// Valid response is an ACK: 12 04 A0 B6
checkNotNullOrEmpty(processedResponse, "processedResponse");
DS2ResponseProcessor.validateResponse(processedResponse);
}
@Override
public EcuInit parseEcuInitResponse(byte[] processedResponse) {
return new DS2EcuInit(parseResponseData(processedResponse));
@ -194,23 +218,34 @@ public final class DS2Protocol implements ProtocolDS2 {
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 (command == SET_ADDRESS_COMMAND) {
length++;
bb.write(content.length); // number of parameters
}
if (readLen.length > 0) {
for (byte[] tmp : content) { // address payload
if (command == READ_PROCEDURE_COMMAND
&& tmp.length == 3) {// legacy ADC def 0x0B020E support
length++;
bb.write((byte) 0x00);
}
else if (command == READ_ADDRESS_COMMAND) {
break; // no content
}
length += tmp.length;
bb.write(tmp);
}
if (readLen.length > 0) { // readMemory, # of bytes to reads
bb.write(readLen);
}
bb.write((byte) 0x00);
bb.write((byte) 0x00); // chksum placeholder
request = bb.toByteArray();
request[1] = (byte) length; // update length value
final byte cs = calculateChecksum(request);
request[request.length - 1] = cs;
} catch (IOException e) {

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2020 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
@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.log4j.Logger;
@ -41,13 +42,18 @@ import com.romraider.logger.ecu.comms.query.EcuQuery;
import com.romraider.logger.ecu.comms.query.EcuQueryRangeTest;
import com.romraider.logger.ecu.definition.EcuData;
import com.romraider.logger.ecu.definition.Module;
import com.romraider.logger.ecu.exception.SerialCommunicationException;
import com.romraider.util.ResourceUtil;
import com.romraider.util.SettingsManager;
public final class DS2LoggerConnection implements LoggerConnection {
private static final Logger LOGGER = getLogger(DS2LoggerConnection.class);
private static final ResourceBundle rb = new ResourceUtil().getBundle(
DS2LoggerConnection.class.getName());
private final LoggerProtocolDS2 protocol;
private final ConnectionManager manager;
Settings settings = SettingsManager.getSettings();
private final Settings settings = SettingsManager.getSettings();
private int queryCount;
public DS2LoggerConnection(ConnectionManager manager) {
checkNotNull(manager, "manager");
@ -85,36 +91,44 @@ public final class DS2LoggerConnection implements LoggerConnection {
Module module,
PollingState pollState) {
// Group the queries into common command groups
final Map<String, Collection<EcuQuery>> groupList = getGroupList(queries);
// for each group populate the queries with results
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")) {
final String groupTest = group.toLowerCase();
// read from procedure [02 XX XX XX PN] PN - Procedure Number<28 (0x1C)
if (groupTest.startsWith("0x0b0x02")) {
for (EcuQuery query : querySet) {
final Collection<EcuQuery> queryList = new ArrayList<EcuQuery>();
queryList.add(query);
request = protocol.constructReadAddressRequest(
request = protocol.constructReadProcedureRequest(
module, queryList);
LOGGER.debug("Mode:" + pollState.getCurrentState() + " " +
module + " Request ---> " + asHex(request));
LOGGER.debug(String.format("Mode:%s %s Procedure request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
response = protocol.constructReadAddressResponse(
queryList, request.length);
protocol.processReadAddressResponses(
protocol.processReadAddressResponse(
queryList,
sendRcv(module, request, response, pollState),
pollState);
}
}
else if (group.equalsIgnoreCase("0x060x00")) {
// read data starting at address [00 SG HI LO NN] NN - number of bytes<249
else if (groupTest.startsWith("0x060x00")) {
final EcuQueryRangeTest range = new EcuQueryRangeTest(querySet);
final Collection<EcuQuery> newQuery = range.validate();
int length = range.getLength();
if (newQuery != null && length > 0) {
request = protocol.constructReadMemoryRange(
module, newQuery, length);
LOGGER.debug("Mode:" + pollState.getCurrentState() + " " +
module + " Request ---> " + asHex(request));
LOGGER.debug(String.format("Mode:%s %s Range request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
response = protocol.constructReadMemoryRangeResponse(
request.length, length);
protocol.processReadMemoryRangeResponse(
@ -127,24 +141,75 @@ public final class DS2LoggerConnection implements LoggerConnection {
queryList.add(query);
request = protocol.constructReadMemoryRequest(
module, queryList);
LOGGER.debug("Mode:" + pollState.getCurrentState() + " " +
module + " Request ---> " + asHex(request));
LOGGER.debug(String.format("Mode:%s %s Memory request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
response = protocol.constructReadAddressResponse(
queryList, request.length);
protocol.processReadAddressResponses(
protocol.processReadAddressResponse(
queryList,
sendRcv(module, request, response, pollState),
pollState);
}
}
}
else {
// Pre-defined Group parameter calls
// #03 Engine Parameters
// #04 Switch Parameters
// #91h Lambda Adaptations
// #92h Other Adaptations
// #93h Timing Correction/Fuel Compensation
else if (groupTest.startsWith("0x0b0x03")
|| groupTest.startsWith("0x0b0x04")
|| groupTest.startsWith("0x0b0x91")
|| groupTest.startsWith("0x0b0x92")
|| groupTest.startsWith("0x0b0x93")) {
request = protocol.constructReadGroupRequest(
module, group);
LOGGER.debug("Mode:" + pollState.getCurrentState() + " " +
module + " Request ---> " + asHex(request));
LOGGER.debug(String.format("Mode:%s %s Group request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
response = protocol.constructReadGroupResponse(
querySet, request.length);
protocol.processReadAddressResponse(
querySet,
sendRcv(module, request, response, pollState),
pollState);
}
// user selected parameter list
// [01 NN B4 B3 B2 B1 B0 ... B4n B3n B2n B1n B0n] NN<33h
else if (groupTest.startsWith("0x0b0x01")) {
// update address list if size or new query changes
if (querySet.size() != queryCount
|| pollState.isNewQuery()) {
// if too many parameters selected then notify user
// to un-select some
if (querySet.size() > 0x32) {
throw new SerialCommunicationException(
rb.getString("TOOLARGE"));
}
// Set new address list
request = protocol.constructSetAddressRequest(
module, querySet);
LOGGER.debug(String.format("Mode:%s %s Load address request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
pollState.setLastState(PollingState.State.STATE_0);
// Response to address list set is just an ACK
response = protocol.constructSetAddressResponse(
request.length);
protocol.validateSetAddressResponse(
sendRcv(module, request, response, pollState));
queryCount = querySet.size();
}
// Read set addresses
request = protocol.constructReadAddressRequest(
module, querySet);
LOGGER.debug(String.format("Mode:%s %s Read addresses request ---> %s",
pollState.getCurrentState(), module, asHex(request)));
pollState.setLastState(PollingState.State.STATE_0);
// Response to address list read is the parameter bytes
response = protocol.constructReadAddressResponse(
querySet, request.length);
protocol.processReadAddressResponses(
querySet,
sendRcv(module, request, response, pollState),
@ -155,11 +220,13 @@ public final class DS2LoggerConnection implements LoggerConnection {
@Override
public void clearLine() {
clearQueryCount();
manager.clearLine();
}
@Override
public void close() {
clearQueryCount();
manager.close();
}
@ -189,7 +256,11 @@ public final class DS2LoggerConnection implements LoggerConnection {
}
}
// Create a map of groups each with a value of a list of queries having the same group
/**
* Return a map of groups each with a value of a list of queries having the same group
* @param queries
* @return Map(Group, Collection(EcuQuery))
*/
private Map<String, Collection<EcuQuery>> getGroupList(Collection<EcuQuery> queries) {
final Map<String, Collection<EcuQuery>> groups = new HashMap<String, Collection<EcuQuery>>();
String group;
@ -219,4 +290,8 @@ public final class DS2LoggerConnection implements LoggerConnection {
module + " Response <--- " + asHex(processedResponse));
return processedResponse;
}
public void clearQueryCount() {
queryCount = -1;
}
}

View File

@ -1,6 +1,6 @@
/*
* RomRaider Open-Source Tuning, Logging and Reflashing
* Copyright (C) 2006-2015 RomRaider.com
* Copyright (C) 2006-2020 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
@ -21,22 +21,24 @@ package com.romraider.logger.ecu.comms.io.protocol;
import java.util.Collection;
import com.romraider.logger.ecu.comms.manager.PollingState;
import com.romraider.logger.ecu.comms.query.EcuQuery;
import com.romraider.logger.ecu.definition.Module;
public interface LoggerProtocolDS2 extends LoggerProtocol {
byte[] constructReadProcedureRequest(Module module,
Collection<EcuQuery> queries);
byte[] constructReadAddressResponse(
Collection<EcuQuery> queries, int requestSize);
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);
@ -45,5 +47,15 @@ public interface LoggerProtocolDS2 extends LoggerProtocol {
public byte[] constructReadMemoryRangeResponse(int requestSize, int length);
void processReadAddressResponse(Collection<EcuQuery> queries,
byte[] response, PollingState pollState);
void processReadMemoryRangeResponse(Collection<EcuQuery> queries, byte[] response);
byte[] constructSetAddressRequest(
Module module, Collection<EcuQuery> queryList);
byte[] constructSetAddressResponse(int length);
void validateSetAddressResponse(byte[] response);
}