All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.pires.obd.commands.ObdCommand Maven / Gradle / Ivy

The newest version!
/**
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.github.pires.obd.commands;

import com.github.pires.obd.exceptions.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;

/**
 * Base OBD command.
 *
 */
public abstract class ObdCommand {

    /**
     * Error classes to be tested in order
     */
    private final Class[] ERROR_CLASSES = {
            UnableToConnectException.class,
            BusInitException.class,
            MisunderstoodCommandException.class,
            NoDataException.class,
            StoppedException.class,
            UnknownErrorException.class,
            UnsupportedCommandException.class
    };
    protected ArrayList buffer = null;
    protected String cmd = null;
    protected boolean useImperialUnits = false;
    protected String rawData = null;
    protected Long responseDelayInMs = null;
    private long start;
    private long end;

    /**
     * Default ctor to use
     *
     * @param command the command to send
     */
    public ObdCommand(String command) {
        this.cmd = command;
        this.buffer = new ArrayList<>();
    }

    /**
     * Prevent empty instantiation
     */
    private ObdCommand() {
    }

    /**
     * Copy ctor.
     *
     * @param other the ObdCommand to copy.
     */
    public ObdCommand(ObdCommand other) {
        this(other.cmd);
    }

    /**
     * Sends the OBD-II request and deals with the response.
     * 

* This method CAN be overriden in fake commands. * * @param in a {@link java.io.InputStream} object. * @param out a {@link java.io.OutputStream} object. * @throws java.io.IOException if any. * @throws java.lang.InterruptedException if any. */ public void run(InputStream in, OutputStream out) throws IOException, InterruptedException { synchronized (ObdCommand.class) {//Only one command can write and read a data in one time. start = System.currentTimeMillis(); sendCommand(out); readResult(in); end = System.currentTimeMillis(); } } /** * Sends the OBD-II request. *

* This method may be overriden in subclasses, such as ObMultiCommand or * TroubleCodesCommand. * * @param out The output stream. * @throws java.io.IOException if any. * @throws java.lang.InterruptedException if any. */ protected void sendCommand(OutputStream out) throws IOException, InterruptedException { // write to OutputStream (i.e.: a BluetoothSocket) with an added // Carriage return out.write((cmd + "\r").getBytes()); out.flush(); if (responseDelayInMs != null && responseDelayInMs > 0) { Thread.sleep(responseDelayInMs); } } /** * Resends this command. * * @param out a {@link java.io.OutputStream} object. * @throws java.io.IOException if any. * @throws java.lang.InterruptedException if any. */ protected void resendCommand(OutputStream out) throws IOException, InterruptedException { out.write("\r".getBytes()); out.flush(); if (responseDelayInMs != null && responseDelayInMs > 0) { Thread.sleep(responseDelayInMs); } } /** * Reads the OBD-II response. *

* This method may be overriden in subclasses, such as ObdMultiCommand. * * @param in a {@link java.io.InputStream} object. * @throws java.io.IOException if any. */ protected void readResult(InputStream in) throws IOException { readRawData(in); checkForErrors(); fillBuffer(); performCalculations(); } /** * This method exists so that for each command, there must be a method that is * called only once to perform calculations. */ protected abstract void performCalculations(); /** *

fillBuffer.

*/ protected void fillBuffer() { rawData = rawData.replaceAll("\\s", ""); //removes all [ \t\n\x0B\f\r] rawData = rawData.replaceAll("(BUS INIT)|(BUSINIT)|(\\.)", ""); if (!rawData.matches("([0-9A-F])+")) { throw new NonNumericResponseException(rawData); } // read string each two chars buffer.clear(); int begin = 0; int end = 2; while (end <= rawData.length()) { buffer.add(Integer.decode("0x" + rawData.substring(begin, end))); begin = end; end += 2; } } /** *

* readRawData.

* * @param in a {@link java.io.InputStream} object. * @throws java.io.IOException if any. */ protected void readRawData(InputStream in) throws IOException { byte b = 0; StringBuilder res = new StringBuilder(); // read until '>' arrives OR end of stream reached char c; // -1 if the end of the stream is reached while (((b = (byte) in.read()) > -1)) { c = (char) b; if (c == '>') // read until '>' arrives { break; } res.append(c); } /* * Imagine the following response 41 0c 00 0d. * * ELM sends strings!! So, ELM puts spaces between each "byte". And pay * attention to the fact that I've put the word byte in quotes, because 41 * is actually TWO bytes (two chars) in the socket. So, we must do some more * processing.. */ rawData = res.toString().replaceAll("SEARCHING", ""); /* * Data may have echo or informative text like "INIT BUS..." or similar. * The response ends with two carriage return characters. So we need to take * everything from the last carriage return before those two (trimmed above). */ //kills multiline.. rawData = rawData.substring(rawData.lastIndexOf(13) + 1); rawData = rawData.replaceAll("\\s", "");//removes all [ \t\n\x0B\f\r] } void checkForErrors() { for (Class errorClass : ERROR_CLASSES) { ResponseException messageError; try { messageError = errorClass.newInstance(); messageError.setCommand(this.cmd); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } if (messageError.isError(rawData)) { throw messageError; } } } /** *

getResult.

* * @return the raw command response in string representation. */ public String getResult() { return rawData; } /** *

getFormattedResult.

* * @return a formatted command response in string representation. */ public abstract String getFormattedResult(); /** *

getCalculatedResult.

* * @return the command response in string representation, without formatting. */ public abstract String getCalculatedResult(); /** *

Getter for the field buffer.

* * @return a list of integers */ protected ArrayList getBuffer() { return buffer; } /** *

useImperialUnits.

* * @return true if imperial units are used, or false otherwise */ public boolean useImperialUnits() { return useImperialUnits; } /** * The unit of the result, as used in {@link #getFormattedResult()} * * @return a String representing a unit or "", never null */ public String getResultUnit() { return "";//no unit by default } /** * Set to 'true' if you want to use imperial units, false otherwise. By * default this value is set to 'false'. * * @param isImperial a boolean. */ public void useImperialUnits(boolean isImperial) { this.useImperialUnits = isImperial; } /** *

getName.

* * @return the OBD command name. */ public abstract String getName(); /** * Time the command waits before returning from #sendCommand() * * @return delay in ms (may be null) */ public Long getResponseTimeDelay() { return responseDelayInMs; } /** * Time the command waits before returning from #sendCommand() * * @param responseDelayInMs a Long (can be null) */ public void setResponseTimeDelay(Long responseDelayInMs) { this.responseDelayInMs = responseDelayInMs; } //fixme resultunit /** *

Getter for the field start.

* * @return a long. */ public long getStart() { return start; } /** *

Setter for the field start.

* * @param start a long. */ public void setStart(long start) { this.start = start; } /** *

Getter for the field end.

* * @return a long. */ public long getEnd() { return end; } /** *

Setter for the field end.

* * @param end a long. */ public void setEnd(long end) { this.end = end; } /** *

getCommandPID.

* * @return a {@link java.lang.String} object. * @since 1.0-RC12 */ public final String getCommandPID() { return cmd.substring(3); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ObdCommand that = (ObdCommand) o; return cmd != null ? cmd.equals(that.cmd) : that.cmd == null; } @Override public int hashCode() { return cmd != null ? cmd.hashCode() : 0; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy