diff --git a/src/main/java/com/romraider/Settings.java b/src/main/java/com/romraider/Settings.java index 12f4a2e9..503966c9 100644 --- a/src/main/java/com/romraider/Settings.java +++ b/src/main/java/com/romraider/Settings.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -155,6 +155,8 @@ public class Settings implements Serializable { private static final String USER_LANGUAGE = "user.language"; private static final String USER_COUNTRY = "user.country"; private static final String EN_US = "en_US"; + private static final String SSM = "SSM"; + private static final String OBD = "OBD"; private final Dimension windowSize = new Dimension(800, 600); private final Point windowLocation = new Point(); @@ -194,7 +196,7 @@ public class Settings implements Serializable { private String loggerPort; private String loggerPortDefault; - private static String loggerProtocol = "SSM"; + private static String loggerProtocol = SSM; private static String loggerDefinitionFilePath; private static String loggerProfileFilePath; private static String loggerOutputDirPath = System.getProperty("user.home"); @@ -782,6 +784,13 @@ public class Settings implements Serializable { return false; } + public boolean isObdProtocol() { + if (loggerProtocol.equals(OBD)) { + return true; + } + return false; + } + public final boolean isUsNumberFormat() { if (userLocale.equalsIgnoreCase(EN_US)) { return true; diff --git a/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDLoggerProtocol.java b/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDLoggerProtocol.java new file mode 100644 index 00000000..aea77276 --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDLoggerProtocol.java @@ -0,0 +1,198 @@ +/* + * 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.obd.iso15765; + +import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.RESPONSE_NON_DATA_BYTES; +import static com.romraider.io.protocol.obd.iso15765.OBDResponseProcessor.extractResponseData; +import static com.romraider.io.protocol.obd.iso15765.OBDResponseProcessor.filterRequestFromResponse; +import static com.romraider.util.HexUtil.asHex; +import static com.romraider.util.ParamChecker.checkNotNull; +import static com.romraider.util.ParamChecker.checkNotNullOrEmpty; +import static java.lang.System.arraycopy; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import com.romraider.io.protocol.Protocol; +import com.romraider.logger.ecu.comms.io.protocol.LoggerProtocolOBD; +import com.romraider.logger.ecu.comms.manager.PollingState; +import com.romraider.logger.ecu.comms.query.EcuInit; +import com.romraider.logger.ecu.comms.query.EcuInitCallback; +import com.romraider.logger.ecu.comms.query.EcuQuery; + +public final class OBDLoggerProtocol implements LoggerProtocolOBD { + private final Protocol protocol = new OBDProtocol(); + + @Override + public byte[] constructEcuInitRequest(byte id) { + return protocol.constructEcuInitRequest(id); + } + + @Override + public byte[] constructEcuResetRequest(byte id) { + return protocol.constructEcuResetRequest(id); + } + + @Override + public byte[] constructReadAddressRequest( + byte id, Collection queries) { + + Collection filteredQueries = filterDuplicates(queries); + return protocol.constructReadAddressRequest( + id, convertToByteAddresses(filteredQueries)); + } + + @Override + public byte[] constructReadPidRequest(byte id, byte[] pid) { + final byte[][] request = new byte[1][pid.length]; + arraycopy(pid, 0, request[0], 0, pid.length); + return protocol.constructReadAddressRequest(id, request); + } + + @Override + public byte[] constructReadAddressResponse( + Collection queries, PollingState pollState) { + + checkNotNullOrEmpty(queries, "queries"); + // four byte - CAN ID + // one byte - Response mode + // one byte - Response pid + // variable bytes of data defined for pid + Collection filteredQueries = filterDuplicates(queries); + int numAddresses = 0; + for (EcuQuery ecuQuery : filteredQueries) { + numAddresses += ecuQuery.getBytes().length; + numAddresses += getDataLength(ecuQuery); + } + return new byte[(numAddresses + RESPONSE_NON_DATA_BYTES)]; + } + + @Override + public byte[] preprocessResponse( + byte[] request, byte[] response, PollingState pollState) { + + return filterRequestFromResponse(request, response, pollState); + } + + @Override + public void processEcuInitResponse(EcuInitCallback callback, byte[] response) { + checkNotNull(callback, "callback"); + checkNotNullOrEmpty(response, "response"); + protocol.checkValidEcuInitResponse(response); + EcuInit ecuInit = protocol.parseEcuInitResponse(response); + callback.callback(ecuInit); + } + + @Override + public void processEcuResetResponse(byte[] response) { + checkNotNullOrEmpty(response, "response"); + protocol.checkValidEcuResetResponse(response); + } + + // processes the response bytes and sets individual responses on corresponding query objects + @Override + public void processReadAddressResponses( + Collection queries, byte[] response, PollingState pollState) { + + checkNotNullOrEmpty(queries, "queries"); + checkNotNullOrEmpty(response, "response"); + final byte[] responseData = extractResponseData(response); + final Collection filteredQueries = filterDuplicates(queries); + final Map addressResults = new HashMap(); + int i = 0; + for (EcuQuery filteredQuery : filteredQueries) { + final int addrLength = filteredQuery.getBytes().length; + final int dataLength = getDataLength(filteredQuery); + final byte[] addr = new byte[addrLength]; + final byte[] data = new byte[dataLength]; + arraycopy(responseData, i, addr, 0, addrLength); + arraycopy(responseData, i + addrLength, data, 0, dataLength); + addressResults.put(asHex(addr), data); + i += addrLength + dataLength; + } + for (EcuQuery query : queries) { + query.setResponse(addressResults.get(query.getHex())); + } + } + + @Override + public Protocol getProtocol() { + return protocol; + } + + @Override + public byte[] constructWriteAddressRequest( + byte id, byte[] writeAddress, byte value) { + + return protocol.constructWriteAddressRequest(id, 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; + for (EcuQuery query : queries) { + byteCount += query.getAddresses().length; + } + final int ADDRESS_SIZE = 1; + // TODO how do we handle variable address lengths ? + final byte[][] addresses = new byte[byteCount][ADDRESS_SIZE]; + int i = 0; + for (EcuQuery query : queries) { + final int addrLength = query.getBytes().length; + final byte[] bytes = query.getBytes(); + for (int j = 0; j < bytes.length / addrLength; j++) { + arraycopy(bytes, j * addrLength, addresses[i++], 0, addrLength); + } + } + return addresses; + } + + 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; + } +} diff --git a/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDProtocol.java b/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDProtocol.java new file mode 100644 index 00000000..d318ac8c --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDProtocol.java @@ -0,0 +1,247 @@ +/* + * 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.obd.iso15765; + +import static com.romraider.util.HexUtil.asBytes; +import static com.romraider.util.HexUtil.asHex; +import static com.romraider.util.ParamChecker.checkGreaterThanZero; +import static com.romraider.util.ParamChecker.checkNotNullOrEmpty; +import static java.lang.System.arraycopy; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; + +import com.romraider.Settings; +import com.romraider.io.connection.ConnectionProperties; +import com.romraider.io.protocol.Protocol; +import com.romraider.logger.ecu.comms.manager.PollingState; +import com.romraider.logger.ecu.comms.query.EcuInit; +import com.romraider.logger.ecu.comms.query.SSMEcuInit; +import com.romraider.logger.ecu.definition.EcuDefinition; +import com.romraider.logger.ecu.exception.InvalidResponseException; +import com.romraider.logger.ecu.exception.UnsupportedProtocolException; +import com.romraider.util.SettingsManager; + +public final class OBDProtocol implements Protocol { + private static final byte[] ECU_TESTER = + new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0xe0}; + private static final byte[] TCU_TESTER = + new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0xe1}; + private static byte[] ECU_CALID = + new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0xe8}; + private static final byte[] TCU_CALID = + new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0xe9}; + private final ByteArrayOutputStream bb = new ByteArrayOutputStream(255); + private static byte[] TESTER = ECU_TESTER; + public static byte[] ECU_ID = ECU_CALID; + public static final byte OBD_INIT_COMMAND = (byte) 0x01; + public static final byte OBD_INIT_RESPONSE = (byte) 0x41; + public static final byte OBD_INFO_COMMAND = (byte) 0x09; + public static final byte OBD_INFO_RESPONSE = (byte) 0x49; + public static final byte OBD_RESET_COMMAND = (byte) 0x04; + public static final byte OBD_RESET_RESPONSE = (byte) 0x44; + public static final byte OBD_NRC = (byte) 0x7F; + public static final int RESPONSE_NON_DATA_BYTES = 5; + + @Override + public byte[] constructEcuInitRequest(byte id) { + checkGreaterThanZero(id, "ECU_ID"); + setIDs(id); + final byte[] request = buildRequest( + OBD_INFO_COMMAND, true, new byte[]{4}); + return request; + } + + @Override + public byte[] constructWriteMemoryRequest( + byte id, byte[] address, byte[] values) { + + throw new UnsupportedProtocolException( + "Write memory command is not supported on OBD for address: " + + asHex(address)); + } + + @Override + public byte[] constructWriteAddressRequest( + byte id, byte[] address, byte value) { + + throw new UnsupportedProtocolException( + "Write Address command is not supported on OBD for address: " + + asHex(address)); + } + + @Override + public byte[] constructReadMemoryRequest( + byte id, byte[] address, int numBytes) { + + throw new UnsupportedProtocolException( + "Read memory command is not supported on OBD for address: " + + asHex(address)); + } + + @Override + public byte[] constructReadAddressRequest(byte id, byte[][] addresses) { + checkGreaterThanZero(id, "ECU_ID"); + checkNotNullOrEmpty(addresses, "addresses"); + setIDs(id); + return buildRequest(OBD_INIT_COMMAND, true, addresses); + } + + @Override + public byte[] preprocessResponse( + byte[] request, byte[] response, PollingState pollState) { + return OBDResponseProcessor.filterRequestFromResponse( + request, response, pollState); + } + + @Override + public byte[] parseResponseData(byte[] processedResponse) { + checkNotNullOrEmpty(processedResponse, "processedResponse"); + return OBDResponseProcessor.extractResponseData(processedResponse); + } + + @Override + public void checkValidEcuInitResponse(byte[] processedResponse) { + checkNotNullOrEmpty(processedResponse, "processedResponse"); + OBDResponseProcessor.validateResponse(processedResponse); + // four byte - CAN ID + // one byte - Response mode + // one byte - Response pid + // null terminated CAL ID string + // 000007E8 49 ..... + byte responseType = processedResponse[4]; + if (responseType != OBD_INFO_RESPONSE) { + throw new InvalidResponseException( + "Unexpected ECU Info response type: " + + asHex(new byte[]{responseType})); + } + } + + @Override + public EcuInit parseEcuInitResponse(byte[] processedResponse) { + checkNotNullOrEmpty(processedResponse, "processedResponse"); + final byte[] ecuInitBytes = parseResponseData(processedResponse); + final byte[] calIdBytes = Arrays.copyOf(ecuInitBytes, 8); + final String calIdStr = new String(calIdBytes); + final Settings settings = SettingsManager.getSettings(); + + final Map defMap = + settings.getLoggerEcuDefinitionMap(); + byte[] ecuIdBytes = new byte[] {0,0,0,0,0}; + // convert CALID to ECUID based on defined ECU defs + for (EcuDefinition ecuDef : defMap.values()) { + if (ecuDef.getCalId().equals(calIdStr)) { + ecuIdBytes = asBytes(ecuDef.getEcuId()); + break; + } + } + + arraycopy(ecuIdBytes, 0, ecuInitBytes, 3, 5); + return new SSMEcuInit(ecuInitBytes); + } + + @Override + public byte[] constructEcuResetRequest(byte id) { + checkGreaterThanZero(id, "ECU_ID"); + // 000007E0 04 + return buildRequest((byte) 0, false, new byte[]{OBD_RESET_COMMAND}); + } + + @Override + public void checkValidEcuResetResponse(byte[] processedResponse) { + checkNotNullOrEmpty(processedResponse, "processedResponse"); + // 000007E8 44 + byte responseType = processedResponse[4]; + if (responseType != OBD_RESET_RESPONSE) { + throw new InvalidResponseException( + "Unexpected OBD Reset response: " + + asHex(processedResponse)); + } + } + + @Override + public void checkValidWriteResponse(byte[] data, byte[] processedResponse) { + } + + @Override + public ConnectionProperties getDefaultConnectionProperties() { + return new ConnectionProperties() { + + public int getBaudRate() { + return 500000; + } + + public void setBaudRate(int b) { + + } + + public int getDataBits() { + return 8; + } + + public int getStopBits() { + return 1; + } + + public int getParity() { + return 0; + } + + public int getConnectTimeout() { + return 2000; + } + + public int getSendTimeout() { + return 55; + } + }; + } + + private byte[] buildRequest( + byte command, + boolean addCommand, + byte[]... content) { + + bb.reset(); + try { + bb.write(TESTER); + if (addCommand) { + bb.write(command); + } + for (byte[] tmp : content) { + bb.write(tmp); + } + } catch (IOException e) { + e.printStackTrace(); + } + return bb.toByteArray(); + } + + private void setIDs(byte id) { + ECU_ID = ECU_CALID; + TESTER = ECU_TESTER; + if (id == 0x18) { + ECU_ID = TCU_CALID; + TESTER = TCU_TESTER; + } + } +} diff --git a/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDResponseProcessor.java b/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDResponseProcessor.java new file mode 100644 index 00000000..5580219c --- /dev/null +++ b/src/main/java/com/romraider/io/protocol/obd/iso15765/OBDResponseProcessor.java @@ -0,0 +1,132 @@ +/* + * 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.obd.iso15765; + +import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.ECU_ID; +import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.OBD_INFO_RESPONSE; +import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.OBD_INIT_RESPONSE; +import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.OBD_NRC; +import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.OBD_RESET_RESPONSE; +import static com.romraider.io.protocol.obd.iso15765.OBDProtocol.RESPONSE_NON_DATA_BYTES; +import static com.romraider.util.ByteUtil.asUnsignedInt; +import static com.romraider.util.HexUtil.asHex; +import static com.romraider.util.ParamChecker.checkNotNullOrEmpty; + +import java.util.Arrays; + +import com.romraider.logger.ecu.comms.manager.PollingState; +import com.romraider.logger.ecu.exception.InvalidResponseException; + +public final class OBDResponseProcessor { + + private OBDResponseProcessor() { + throw new UnsupportedOperationException(); + } + + public final static byte[] filterRequestFromResponse( + byte[] request, byte[] response, PollingState pollState) { + + checkNotNullOrEmpty(response, "response"); + return response; + } + + public final static void validateResponse(byte[] response) { + checkNotNullOrEmpty(response, "response"); + assertTrue(response.length > RESPONSE_NON_DATA_BYTES, + "Invalid response length"); + assertEquals(ECU_ID, response, "Invalid ECU id"); + if (response[4] == OBD_NRC) { + assertNrc(OBD_NRC, response[4], response[5], response[6], + "Request type not supported"); + } + assertOneOf(new byte[]{ + OBD_INIT_RESPONSE, OBD_INFO_RESPONSE, OBD_RESET_RESPONSE}, + response[4], "Invalid response code"); + } + + public final static byte[] extractResponseData(byte[] response) { + checkNotNullOrEmpty(response, "response"); + // ECU_addr response_mode pid1 response_data1 ... [pid6 response_data6] + validateResponse(response); + final byte[] data = new byte[response.length - RESPONSE_NON_DATA_BYTES]; + System.arraycopy(response, RESPONSE_NON_DATA_BYTES, data, 0, data.length); + return data; + } + + + private final static void assertTrue(boolean condition, String msg) { + if (!condition) { + throw new InvalidResponseException(msg); + } + } + + private final static void assertNrc( + byte expected, byte actual, byte command, byte code, String msg) { + + if (actual == expected) { + String ec = "unsupported."; + if (code == 0x12) { + ec = "request sub-function is not supported."; + } + if (code == 0x13) { + ec = "invalid format or length."; + } + if (code == 0x22) { + ec = "is supported but data is currently not available."; + } + throw new InvalidResponseException(String.format( + "%s. Command: %s, %s", + msg, asHex(command), ec)); + } + } + + private final static void assertEquals( + byte[] expected, byte[] actual, String msg) { + + final byte[] idBytes = Arrays.copyOf(actual, 4); + final int idExpected = asUnsignedInt(expected); + final int idActual = asUnsignedInt(idBytes); + if (idActual != idExpected) { + throw new InvalidResponseException(String.format( + "%s. Expected: %s. Actual: %s.", + msg, asHex(expected), asHex(idBytes))); + } + } + + private final static void assertOneOf( + byte[] validOptions, byte actual, String msg) { + + for (byte option : validOptions) { + if (option == actual) { + return; + } + } + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < validOptions.length; i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(asHex(validOptions[i])); + } + throw new InvalidResponseException(String.format( + "%s. Expected one of [%s]. Actual: %s.", + msg, builder.toString(), asHex(actual))); + } +} diff --git a/src/main/java/com/romraider/logger/ecu/comms/io/connection/LoggerConnectionFactory.java b/src/main/java/com/romraider/logger/ecu/comms/io/connection/LoggerConnectionFactory.java index ff9baa90..cab72116 100644 --- a/src/main/java/com/romraider/logger/ecu/comms/io/connection/LoggerConnectionFactory.java +++ b/src/main/java/com/romraider/logger/ecu/comms/io/connection/LoggerConnectionFactory.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2012 RomRaider.com + * 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 @@ -48,7 +48,8 @@ public final class LoggerConnectionFactory { ConnectionManager.class).newInstance(manager); } catch (Exception e) { manager.close(); - throw new UnsupportedProtocolException(e.getCause().getMessage(), e); + throw new UnsupportedProtocolException( + protocolName, e); } } } diff --git a/src/main/java/com/romraider/logger/ecu/comms/io/connection/OBDLoggerConnection.java b/src/main/java/com/romraider/logger/ecu/comms/io/connection/OBDLoggerConnection.java new file mode 100644 index 00000000..0822485f --- /dev/null +++ b/src/main/java/com/romraider/logger/ecu/comms/io/connection/OBDLoggerConnection.java @@ -0,0 +1,176 @@ +/* + * 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.Map; + +import org.apache.log4j.Logger; + +import com.romraider.Settings; +import com.romraider.util.SettingsManager; +import com.romraider.io.connection.ConnectionManager; +import com.romraider.io.protocol.ProtocolFactory; +import com.romraider.logger.ecu.comms.io.protocol.LoggerProtocolOBD; +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; + +public final class OBDLoggerConnection implements LoggerConnection { + private static final Logger LOGGER = getLogger(OBDLoggerConnection.class); + private final LoggerProtocolOBD protocol; + private final ConnectionManager manager; + private Collection obdQueries = new ArrayList(); + + public OBDLoggerConnection(ConnectionManager manager) { + checkNotNull(manager, "manager"); + this.manager = manager; + final Settings settings = SettingsManager.getSettings(); + this.protocol = (LoggerProtocolOBD) ProtocolFactory.getProtocol( + settings.getLoggerProtocol(), + settings.getTransportProtocol()); + } + + @Override + public void ecuReset(byte id) { + byte[] request = protocol.constructEcuResetRequest(id); + LOGGER.debug(String.format("OBD Reset Request ---> %s", + asHex(request))); + byte[] response = manager.send(request); + byte[] processedResponse = protocol.preprocessResponse( + request, response, new PollingStateImpl()); + LOGGER.debug(String.format("OBD Reset Response <--- %s", + asHex(processedResponse))); + protocol.processEcuResetResponse(processedResponse); + } + + @Override + // Build an init string similar to the SSM version so the logger definition + // can reference supported parameters with ecubyte/bit attributes. + public void ecuInit(EcuInitCallback callback, byte id) { + final byte[] processedResponse = new byte[46]; + final byte[] request = protocol.constructEcuInitRequest(id); + LOGGER.debug(String.format("OBD Calibration ID Request ---> %s", + asHex(request))); + final byte[] tmp = manager.send(request); + final byte[] response = protocol.preprocessResponse( + request, tmp, new PollingStateImpl()); + LOGGER.debug(String.format("OBD Calibration ID Response <--- %s", + asHex(response))); + System.arraycopy(response, 0, processedResponse, 0, response.length); + int j = 7; + while (response[j] != 0 && j < response.length) { j++; } + final byte[] calIdStr = new byte[j - 7]; + System.arraycopy(response, 7, calIdStr, 0, j - 7); + System.arraycopy(calIdStr, 0, processedResponse, 5, 8); + LOGGER.info(String.format("OBD Calibration ID: %s", new String(calIdStr))); + + final byte[] supportedPidsPid = { + (byte) 0x00, (byte) 0x20, (byte) 0x40, (byte) 0x60, + (byte) 0x80, (byte) 0xA0, (byte) 0xC0, (byte) 0xE0}; + int i = 13; + for (byte pid : supportedPidsPid) { + final byte[] pidRequest = protocol.constructReadPidRequest( + id, new byte[]{pid}); + LOGGER.debug(String.format("OBD PID Group %02X Request ---> %s", + pid, asHex(pidRequest))); + final byte[] pidtmp = manager.send(pidRequest); + final byte[] pidPpResponse = protocol.preprocessResponse( + pidRequest, pidtmp, new PollingStateImpl()); + LOGGER.debug(String.format("OBD PID Group %02X Response <--- %s", + pid, asHex(pidPpResponse))); + System.arraycopy(pidPpResponse, 6, processedResponse, i, 4); + i = i + 4; + if ((pidPpResponse[pidPpResponse.length - 1] & 0x01) == 0) break; + } + + // Check if PID 0x65 is supported and if so read it to obtain the Aux + // Input support bits. Map the first byte into the init string. This + // byte can be referenced as byte 40 by the ecubyte/bit attributes in + // the logger definition to indicate supported switches. + if ((processedResponse[25] & 0x08) > 0) { + final byte[] aiRequest = protocol.constructReadPidRequest( + id, new byte[]{0x65}); + LOGGER.debug(String.format( + "OBD Auxiliary Inputs Support Request ---> %s", + asHex(aiRequest))); + final byte[] aiResponse = manager.send(aiRequest); + final byte[] aiPpResponse = protocol.preprocessResponse( + aiRequest, aiResponse, new PollingStateImpl()); + LOGGER.debug(String.format( + "OBD Auxiliary Inputs Support Response <--- %s", + asHex(aiPpResponse))); + System.arraycopy(aiPpResponse, 6, processedResponse, 45, 1); + } + LOGGER.debug(String.format("OBD Init Response <--- %s", + asHex(processedResponse))); // contains CALID not ECUID + protocol.processEcuInitResponse(callback, processedResponse); + } + + @Override + public final void sendAddressReads( + Collection queries, + byte id, + PollingState pollState) { + + final int obdQueryListLength = queries.size(); + for (int i = 0; i < obdQueryListLength; i += 6) { + for (int j = i; (j < i + 6) && (j < obdQueryListLength); j++) { + obdQueries.add(((ArrayList) queries).get(j)); + } + final byte[] request = protocol.constructReadAddressRequest( + id, obdQueries); + LOGGER.debug(String.format("Mode:%d OBD Request ---> %s", + pollState.getCurrentState(), asHex(request))); + + final byte[] response = protocol.constructReadAddressResponse( + obdQueries, pollState); + manager.send(request, response, pollState); + final byte[] processedResponse = protocol.preprocessResponse( + request, response, pollState); + LOGGER.debug(String.format("Mode:%d OBD Response <--- %s", + pollState.getCurrentState(), asHex(processedResponse))); + protocol.processReadAddressResponses( + obdQueries, processedResponse, pollState); + obdQueries.clear(); + } + } + + @Override + public void clearLine() { + manager.clearLine(); + } + + @Override + public void close() { + manager.close(); + } + + @Override + public void sendAddressWrites(Map writeQueries, byte id) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/romraider/logger/ecu/comms/io/protocol/LoggerProtocolOBD.java b/src/main/java/com/romraider/logger/ecu/comms/io/protocol/LoggerProtocolOBD.java new file mode 100644 index 00000000..a4c48f13 --- /dev/null +++ b/src/main/java/com/romraider/logger/ecu/comms/io/protocol/LoggerProtocolOBD.java @@ -0,0 +1,26 @@ +/* + * 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; + + +public interface LoggerProtocolOBD extends LoggerProtocol { + + byte[] constructReadPidRequest(byte id, byte[] pid); +} diff --git a/src/main/java/com/romraider/logger/ecu/comms/manager/QueryManagerImpl.java b/src/main/java/com/romraider/logger/ecu/comms/manager/QueryManagerImpl.java index b7456133..5b574125 100644 --- a/src/main/java/com/romraider/logger/ecu/comms/manager/QueryManagerImpl.java +++ b/src/main/java/com/romraider/logger/ecu/comms/manager/QueryManagerImpl.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2012 RomRaider.com + * 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 @@ -66,6 +66,7 @@ public final class QueryManagerImpl implements QueryManager { private final Map addList = new HashMap(); private final List removeList = new ArrayList(); private static final PollingState pollState = new PollingStateImpl(); + private static final Settings settings = SettingsManager.getSettings(); private static final String ECU = "ECU"; private static final String TCU = "TCU"; private static final String EXT = "Externals"; @@ -141,7 +142,7 @@ public final class QueryManagerImpl implements QueryManager { started = true; queryManagerThread = Thread.currentThread(); LOGGER.debug("QueryManager started."); - Settings settings = SettingsManager.getSettings(); + try { stop = false; while (!stop) { @@ -177,7 +178,6 @@ public final class QueryManagerImpl implements QueryManager { } try { - Settings settings = SettingsManager.getSettings(); LoggerConnection connection = getConnection(settings.getLoggerProtocol(), settings.getLoggerPort(), @@ -223,7 +223,6 @@ public final class QueryManagerImpl implements QueryManager { int count = 0; try { txManager.start(); - Settings settings = SettingsManager.getSettings(); boolean lastPollState = settings.isFastPoll(); while (!stop) { pollState.setFastPoll(settings.isFastPoll()); @@ -311,7 +310,7 @@ public final class QueryManagerImpl implements QueryManager { private void sendEcuQueries(TransmissionManager txManager) { final List ecuQueries = filterEcuQueries(queryMap.values()); if (fileLoggerQuery != null - && SettingsManager.getSettings().isFileLoggingControllerSwitchActive()) + && settings.isFileLoggingControllerSwitchActive()) ecuQueries.add(fileLoggerQuery); txManager.sendQueries(ecuQueries, pollState); } @@ -332,7 +331,8 @@ public final class QueryManagerImpl implements QueryManager { } private void handleQueryResponse() { - monitor.monitorFileLoggerSwitch(fileLoggerQuery.getResponse()); + if (settings.isFileLoggingControllerSwitchActive()) + monitor.monitorFileLoggerSwitch(fileLoggerQuery.getResponse()); final Response response = buildResponse(queryMap.values()); for (final DataUpdateHandler dataUpdateHandler : dataUpdateHandlers) { runAsDaemon(new Runnable() { @@ -407,10 +407,10 @@ public final class QueryManagerImpl implements QueryManager { if (pollState.isFastPoll()) { state = "Fast-K:"; } - if (SettingsManager.getSettings().getTransportProtocol().equals("ISO15765")) { + if (settings.getTransportProtocol().equals("ISO15765")) { state = "CAN bus:"; } - if (SettingsManager.getSettings().isLogExternalsOnly()) { + if (settings.isLogExternalsOnly()) { state = "Externals:"; } double duration = (System.currentTimeMillis() - start) / 1000.0; diff --git a/src/main/java/com/romraider/logger/ecu/definition/EcuDataConvertor.java b/src/main/java/com/romraider/logger/ecu/definition/EcuDataConvertor.java index d8781701..cc88acaa 100644 --- a/src/main/java/com/romraider/logger/ecu/definition/EcuDataConvertor.java +++ b/src/main/java/com/romraider/logger/ecu/definition/EcuDataConvertor.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -35,4 +35,6 @@ public interface EcuDataConvertor { String getFormat(); String getExpression(); + + String getDataType(); } diff --git a/src/main/java/com/romraider/logger/ecu/definition/EcuDerivedParameterConvertorImpl.java b/src/main/java/com/romraider/logger/ecu/definition/EcuDerivedParameterConvertorImpl.java index 574c9a71..4a0a6562 100644 --- a/src/main/java/com/romraider/logger/ecu/definition/EcuDerivedParameterConvertorImpl.java +++ b/src/main/java/com/romraider/logger/ecu/definition/EcuDerivedParameterConvertorImpl.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -162,4 +162,9 @@ public final class EcuDerivedParameterConvertorImpl implements EcuDerivedParamet } } } + + @Override + public String getDataType() { + return null; + } } diff --git a/src/main/java/com/romraider/logger/ecu/definition/EcuDtcConvertorImpl.java b/src/main/java/com/romraider/logger/ecu/definition/EcuDtcConvertorImpl.java index 551429c0..f60b4655 100644 --- a/src/main/java/com/romraider/logger/ecu/definition/EcuDtcConvertorImpl.java +++ b/src/main/java/com/romraider/logger/ecu/definition/EcuDtcConvertorImpl.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -70,4 +70,9 @@ public final class EcuDtcConvertorImpl implements EcuDataConvertor { public String getExpression() { return "x"; } + + @Override + public String getDataType() { + return null; + } } diff --git a/src/main/java/com/romraider/logger/ecu/definition/EcuParameterConvertorImpl.java b/src/main/java/com/romraider/logger/ecu/definition/EcuParameterConvertorImpl.java index 8bd1e0f3..24a03218 100644 --- a/src/main/java/com/romraider/logger/ecu/definition/EcuParameterConvertorImpl.java +++ b/src/main/java/com/romraider/logger/ecu/definition/EcuParameterConvertorImpl.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -26,7 +26,6 @@ import static com.romraider.util.ByteUtil.asUnsignedInt; import static com.romraider.util.JEPUtil.evaluate; import static com.romraider.util.ParamChecker.checkNotNull; import static com.romraider.util.ParamChecker.checkNotNullOrEmpty; -import static com.romraider.util.ParamChecker.isValidBit; import java.text.DecimalFormat; import java.util.HashMap; @@ -59,20 +58,20 @@ public final class EcuParameterConvertorImpl implements EcuDataConvertor { this.expression = expression; this.format = new DecimalFormat(format); this.bit = bit; - this.dataType = dataType; + this.dataType = (dataType == null ? "uint8" : dataType); this.replaceMap = replaceMap; this.gaugeMinMax = gaugeMinMax; } public double convert(byte[] bytes) { - if (isValidBit(bit)) { - return (bytes[0] & (1 << bit)) > 0 ? 1 : 0; + if (bit >= 0 && bit <= 31) { + return (asUnsignedInt(bytes) & (1 << bit)) != 0 ? 1 : 0; } else { double value = 0; - if (dataType != null && dataType.equalsIgnoreCase(FLOAT)) { + if (dataType.equalsIgnoreCase(FLOAT)) { value = (double) asFloat(bytes, 0 , bytes.length); } - else if (dataType != null && dataType.startsWith(INT)) { + else if (dataType.toLowerCase().startsWith(INT)) { value = (double) asSignedInt(bytes); } else { @@ -111,4 +110,9 @@ public final class EcuParameterConvertorImpl implements EcuDataConvertor { public String getExpression() { return expression; } + + @Override + public String getDataType() { + return dataType; + } } diff --git a/src/main/java/com/romraider/logger/ecu/definition/EcuSwitchConvertorImpl.java b/src/main/java/com/romraider/logger/ecu/definition/EcuSwitchConvertorImpl.java index b217f1bf..3b4fba20 100644 --- a/src/main/java/com/romraider/logger/ecu/definition/EcuSwitchConvertorImpl.java +++ b/src/main/java/com/romraider/logger/ecu/definition/EcuSwitchConvertorImpl.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -60,4 +60,9 @@ public final class EcuSwitchConvertorImpl implements EcuDataConvertor { public String getExpression() { return "x"; } + + @Override + public String getDataType() { + return null; + } } diff --git a/src/main/java/com/romraider/logger/ecu/definition/ExternalDataConvertorImpl.java b/src/main/java/com/romraider/logger/ecu/definition/ExternalDataConvertorImpl.java index 96588715..0e4fbca3 100644 --- a/src/main/java/com/romraider/logger/ecu/definition/ExternalDataConvertorImpl.java +++ b/src/main/java/com/romraider/logger/ecu/definition/ExternalDataConvertorImpl.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -73,4 +73,9 @@ public final class ExternalDataConvertorImpl implements EcuDataConvertor { public String getExpression() { return expression; } + + @Override + public String getDataType() { + return null; + } } diff --git a/src/main/java/com/romraider/logger/ecu/ui/swing/menubar/EcuLoggerMenuBar.java b/src/main/java/com/romraider/logger/ecu/ui/swing/menubar/EcuLoggerMenuBar.java index 5833de0c..a1abb880 100644 --- a/src/main/java/com/romraider/logger/ecu/ui/swing/menubar/EcuLoggerMenuBar.java +++ b/src/main/java/com/romraider/logger/ecu/ui/swing/menubar/EcuLoggerMenuBar.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2013 RomRaider.com + * 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 @@ -75,6 +75,7 @@ import com.romraider.logger.ecu.ui.swing.menubar.action.LogFileNumberFormatActio import com.romraider.logger.ecu.ui.swing.menubar.action.LoggerDebugLocationAction; import com.romraider.logger.ecu.ui.swing.menubar.action.LoggerDebuggingLevelAction; import com.romraider.logger.ecu.ui.swing.menubar.action.LoggerDefinitionLocationAction; +import com.romraider.logger.ecu.ui.swing.menubar.action.ObdModeAction; import com.romraider.logger.ecu.ui.swing.menubar.action.ReadEcuCodesAction; import com.romraider.logger.ecu.ui.swing.menubar.action.ReloadProfileAction; import com.romraider.logger.ecu.ui.swing.menubar.action.ResetConnectionAction; @@ -92,7 +93,7 @@ import com.romraider.util.SettingsManager; public class EcuLoggerMenuBar extends JMenuBar { private static final long serialVersionUID = 7081586516953740186L; - Settings settings = SettingsManager.getSettings(); + final Settings settings = SettingsManager.getSettings(); public EcuLoggerMenuBar(EcuLogger logger, List externalDataSources) { @@ -120,8 +121,11 @@ public class EcuLoggerMenuBar extends JMenuBar { settingsMenu.add(fastPoll); RadioButtonMenuItem canBus = new RadioButtonMenuItem("CAN bus Logging (2007+)", VK_N, getKeyStroke(VK_N, CTRL_MASK), new CanBusModeAction(logger), settings.isCanBus()); canBus.setToolTipText("Select to enable logging via CAN bus using a J2534 compatible cable"); + RadioButtonMenuItem obdProtocol = new RadioButtonMenuItem("OBD Logging Protocol", VK_B, getKeyStroke(VK_B, ALT_MASK), new ObdModeAction(logger), settings.isObdProtocol()); + obdProtocol.setToolTipText("Select to switch logging comminucations protocol to OBD. Only supported for CAN bus using a J2534 compatible cable."); if (isPlatform(WINDOWS)) { settingsMenu.add(canBus); + settingsMenu.add(obdProtocol); } settingsMenu.add(new JSeparator()); settingsMenu.add(new RadioButtonMenuItem("Use Absolute Timestamp In Log File", VK_T, getKeyStroke(VK_T, CTRL_MASK), new LogFileAbsoluteTimestampAction(logger), logger.getSettings().isFileLoggingAbsoluteTimestamp())); diff --git a/src/main/java/com/romraider/logger/ecu/ui/swing/menubar/action/ObdModeAction.java b/src/main/java/com/romraider/logger/ecu/ui/swing/menubar/action/ObdModeAction.java new file mode 100644 index 00000000..f4e49d63 --- /dev/null +++ b/src/main/java/com/romraider/logger/ecu/ui/swing/menubar/action/ObdModeAction.java @@ -0,0 +1,70 @@ +/* + * 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.ui.swing.menubar.action; + +import static javax.swing.JOptionPane.OK_OPTION; +import static javax.swing.JOptionPane.QUESTION_MESSAGE; +import static javax.swing.JOptionPane.YES_NO_OPTION; +import static javax.swing.JOptionPane.showConfirmDialog; + +import java.awt.event.ActionEvent; + +import com.romraider.Settings; +import com.romraider.logger.ecu.EcuLogger; +import com.romraider.swing.menubar.action.AbstractAction; +import com.romraider.util.SettingsManager; + +public final class ObdModeAction extends AbstractAction { + + public ObdModeAction(EcuLogger logger) { + super(logger); + } + + public void actionPerformed(ActionEvent actionEvent) { + final Settings settings = SettingsManager.getSettings(); + try { + logger.stopLogging(); + if ((Boolean) getValue(SELECTED_KEY) && + !settings.isObdProtocol() && + showConfirmation() == OK_OPTION) { + settings.setTransportProtocol("ISO15765"); + settings.setLoggerProtocol("OBD"); + } + else { + settings.setLoggerProtocol("SSM"); + } + logger.loadLoggerParams(); + logger.startLogging(); + } + catch (Exception e) { + logger.reportError(e); + } + } + + private final int showConfirmation() { + return showConfirmDialog(logger, + "Confirm switching to the OBD communications protocol.\n" + + "This mode is only supported for CAN enabled ECUs using " + + "a J2534 compatible cable.", + "OBD Comminucations Mode", + YES_NO_OPTION, + QUESTION_MESSAGE); + } +} diff --git a/src/main/java/com/romraider/util/HexUtil.java b/src/main/java/com/romraider/util/HexUtil.java index e021e462..d40c7ead 100644 --- a/src/main/java/com/romraider/util/HexUtil.java +++ b/src/main/java/com/romraider/util/HexUtil.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2012 RomRaider.com + * 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 @@ -28,7 +28,7 @@ public final class HexUtil { return asHex(new byte[]{b}); } - public static String asHex(byte in[]) { + public static String asHex(byte[] in) { return bytesToHex(in).toUpperCase(); } diff --git a/src/main/java/com/romraider/util/JEPUtil.java b/src/main/java/com/romraider/util/JEPUtil.java index 1cce323d..bb7f1287 100644 --- a/src/main/java/com/romraider/util/JEPUtil.java +++ b/src/main/java/com/romraider/util/JEPUtil.java @@ -1,6 +1,6 @@ /* * RomRaider Open-Source Tuning, Logging and Reflashing - * Copyright (C) 2006-2012 RomRaider.com + * 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 @@ -28,7 +28,8 @@ public final class JEPUtil { } public static double evaluate(String expression, double value) { - JEP parser = new JEP(); + final JEP parser = new JEP(); + parser.addStandardFunctions(); parser.initSymTab(); // clear the contents of the symbol table parser.addVariable("x", value); parser.parseExpression(expression); @@ -36,7 +37,7 @@ public final class JEPUtil { } public static double evaluate(String expression, Map valueMap) { - JEP parser = new JEP(); + final JEP parser = new JEP(); parser.initSymTab(); // clear the contents of the symbol table for (String id : valueMap.keySet()) { parser.addVariable(id, valueMap.get(id));