edgent-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject [1/5] incubator-quarks git commit: ELM327 protocol layer
Date Fri, 01 Apr 2016 16:54:51 GMT
Repository: incubator-quarks
Updated Branches:
  refs/heads/master 35c821cb8 -> a507e342c


ELM327 protocol layer


Project: http://git-wip-us.apache.org/repos/asf/incubator-quarks/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-quarks/commit/eb267121
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quarks/tree/eb267121
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quarks/diff/eb267121

Branch: refs/heads/master
Commit: eb267121209412d5b716f14c414c9f83be96b045
Parents: 0b58e15
Author: Dan Debrunner <djd@debrunners.com>
Authored: Tue Mar 29 08:27:06 2016 -0700
Committer: Dan Debrunner <djd@debrunners.com>
Committed: Tue Mar 29 08:27:06 2016 -0700

----------------------------------------------------------------------
 samples/connectors/build.xml                    |   1 +
 .../quarks/samples/connectors/elm327/Cmd.java   |  76 ++++++++++
 .../connectors/elm327/ELM327Streams.java        |  70 +++++++++
 .../samples/connectors/elm327/Elm327Cmds.java   |  63 +++++++++
 .../samples/connectors/elm327/Pids01.java       | 141 +++++++++++++++++++
 .../samples/connectors/elm327/package-info.java |  27 ++++
 .../elm327/runtime/CommandExecutor.java         | 118 ++++++++++++++++
 7 files changed, 496 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/eb267121/samples/connectors/build.xml
----------------------------------------------------------------------
diff --git a/samples/connectors/build.xml b/samples/connectors/build.xml
index 964a5dd..84d2d5a 100644
--- a/samples/connectors/build.xml
+++ b/samples/connectors/build.xml
@@ -13,6 +13,7 @@
     <pathelement location="${quarks.connectors}/file/lib/quarks.connectors.file.jar"/>
     <pathelement location="${quarks.connectors}/iotf/lib/quarks.connectors.iotf.jar"/>
     <pathelement location="${quarks.connectors}/jdbc/lib/quarks.connectors.jdbc.jar"/>
+    <pathelement location="${quarks.connectors}/serial/lib/quarks.connectors.serial.jar"/>
     <pathelement location="${lib}/quarks.samples.topology.jar"/>
     <pathelement location="${lib}/quarks.samples.utils.jar"/>
     <path refid="quarks.ext.classpath" />

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/eb267121/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Cmd.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Cmd.java b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Cmd.java
new file mode 100644
index 0000000..86873be
--- /dev/null
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Cmd.java
@@ -0,0 +1,76 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 quarks.samples.connectors.elm327;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import com.google.gson.JsonObject;
+
+/**
+ * ELM327 and OBD-II command interface.
+ *
+ */
+public interface Cmd {
+    /**
+     * Key ({@value}) for PID identifier in JSON result.
+     */
+    String PID = "pid";
+
+    /**
+     * Key ({@value}) for timestamp in JSON result. Timestamp value is the
+     * number of milliseconds since the 1907 epoch.
+     */
+    String TS = "ts";
+    
+    /**
+     * Key ({@value}) for the returned value in JSON result.
+     * May not be present.
+     */
+    String VALUE = "value";
+
+    /**
+     * How the command is written to the serial port.
+     * 
+     * @param out
+     *            OutputStream to write bytes to.
+     * @throws IOException
+     *             Exception writing bytes.
+     */
+    void writeCmd(OutputStream out) throws IOException;
+
+    /**
+     * Process the reply into a result.
+     * 
+     * @param result
+     *            JSON object to populate with the result.
+     * @param reply
+     *            Bytes that were returned from the command execution.
+     *            
+     * @return {@code true} result is valid, {@code false} otherwise.
+     */
+    boolean result(JsonObject result, byte[] reply);
+
+    /**
+     * Unique identifier of the command.
+     * 
+     * @return Unique identifier of the command.
+     */
+    String id();
+}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/eb267121/samples/connectors/src/main/java/quarks/samples/connectors/elm327/ELM327Streams.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/elm327/ELM327Streams.java
b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/ELM327Streams.java
new file mode 100644
index 0000000..689c00d
--- /dev/null
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/ELM327Streams.java
@@ -0,0 +1,70 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 quarks.samples.connectors.elm327;
+
+import java.util.concurrent.TimeUnit;
+
+import com.google.gson.JsonArray;
+
+import quarks.samples.connectors.elm327.runtime.CommandExecutor;
+import quarks.connectors.serial.SerialDevice;
+import quarks.function.Supplier;
+import quarks.topology.TStream;
+
+/**
+ * Streams fetching OBD-II data from an ELM327 through
+ * a serial device.
+ *
+ * @see <a href="https://en.wikipedia.org/wiki/ELM327">ELM327</a>
+ */
+public class ELM327Streams {
+	
+    /**
+     * Periodically execute a number of ELM327 commands.
+     * Each tuple on the returned stream is a JSON array containing
+     * the result for each command.
+     * <BR>
+     * Each result is a JSON object containing the
+     * {@link Cmd#id() command identifier} with key {@link Cmd#PID pid}
+     * and any result set by the individual command, typically with
+     * the key {@link Cmd#VALUE value}.
+     * 
+     * @param device Serial device the ELM327 is connected to.
+     * @param period Period to poll.
+     * @param unit Unit of {@code period}.
+     * @param cmds Commands to execute.
+     * @return Stream containing the results of the command exections.
+     */
+	public static TStream<JsonArray> poll(SerialDevice device, long period, TimeUnit unit,
Cmd ... cmds) {
+		
+		Supplier<JsonArray> data = device.getSource(
+				port ->
+		{
+			JsonArray array = new JsonArray();
+			for (Cmd cmd : cmds) {
+				array.add(CommandExecutor.execute(cmd, port.getOutput(), port.getInput()));
+			}
+			return array;
+			
+		});
+		
+		return device.topology().poll(data, period, unit);
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/eb267121/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Elm327Cmds.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Elm327Cmds.java
b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Elm327Cmds.java
new file mode 100644
index 0000000..eae3231
--- /dev/null
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Elm327Cmds.java
@@ -0,0 +1,63 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 quarks.samples.connectors.elm327;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+import com.google.gson.JsonObject;
+
+/**
+ * ELM327 commands.
+ * 
+ * 
+ */
+public enum Elm327Cmds implements Cmd {
+
+    INIT("ATZ"),
+    ECHO_OFF("ATE0"),
+    PROTOCOL_3("ATSP3"),
+    PROTOCOL_5("ATSP5"),
+    BYPASS_INIT("ATBI"),
+    FAST_INIT("ATFI"),
+    SLOW_INIT("ATSI"),;
+
+    private byte[] cmd;
+
+    Elm327Cmds(String code) {
+        cmd = (code + "\r").getBytes(StandardCharsets.US_ASCII);
+    }
+
+    @Override
+    public void writeCmd(OutputStream out) throws IOException {
+        out.write(cmd);
+    }
+
+    @Override
+    public boolean result(JsonObject result, byte[] data) {
+        return true;
+    }
+
+    @Override
+    public String id() {
+        return name();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/eb267121/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Pids01.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Pids01.java
b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Pids01.java
new file mode 100644
index 0000000..0860137
--- /dev/null
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/Pids01.java
@@ -0,0 +1,141 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 quarks.samples.connectors.elm327;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+import com.google.gson.JsonObject;
+
+import quarks.samples.connectors.elm327.runtime.CommandExecutor;
+
+/**
+ * OBD-II Standard Mode 01 Pids.
+ *
+ * 
+ * @see <a href="https://en.wikipedia.org/wiki/OBD-II_PIDs#Mode_01">OBD-II Mode 01
Pids</a>
+ */
+public enum Pids01 implements Cmd {
+    
+    /**
+     * Get the list of available PIDs.
+     */
+	AVAILABLE_PIDS("00"),
+	
+	/**
+	 * Engine coolant temperature in °C.
+	 */
+	ENGINE_COOLANT_TEMP("05") {
+		@Override
+		protected boolean decode(JsonObject result, byte[] reply) {
+			
+			int[] binary = CommandExecutor.binary(reply, 4, 2);
+			
+			int c = binary[0] - 40;
+			result.addProperty(VALUE, c);
+			
+			return true;
+		}
+	},
+
+	/**
+	 * Engine speed in rpm.
+	 */
+	RPM("0C") {
+		@Override
+		protected boolean decode(JsonObject result, byte[] reply) {
+			
+			int[] binary = CommandExecutor.binary(reply, 4, 4);
+			int rpm = ((binary[0] * 256) + binary[1])/4;
+			result.addProperty(VALUE, rpm);
+			
+			return true;
+		}
+	},
+	
+	/**
+	 * Vehicle speed in km/h.
+	 */
+	SPEED("0D"){
+		@Override
+		protected boolean decode(JsonObject result, byte[] reply) {
+			
+			int[] binary = CommandExecutor.binary(reply, 4, 2);
+			
+			result.addProperty(VALUE, binary[0]);
+			
+			return true;
+		}
+	},
+	
+	/**
+     * Engine air intake temperature in °C.
+     */
+	AIR_INTAKE_TEMP("0F"){
+		@Override
+		protected boolean decode(JsonObject result, byte[] reply) {
+			
+			int[] binary = CommandExecutor.binary(reply, 4, 2);
+			
+			int c = binary[0] - 40;
+			result.addProperty(VALUE, c);
+			
+			return true;
+		}
+	},
+	;
+
+    private final String pid;
+	private final byte[] cmd;
+	
+	Pids01(String pid) {
+		this.pid = pid;
+		cmd = ("01" + pid + "1\r").getBytes(StandardCharsets.US_ASCII);
+	}
+	
+	public String id() {
+		return pid;
+	}
+	
+	@Override
+	public void writeCmd(OutputStream out) throws IOException {
+		out.write(cmd);
+	}
+	@Override
+	public final boolean result(JsonObject result, byte[] data) {
+		return validateReply(data) && decode(result, data);
+	}
+	 boolean decode(JsonObject result, byte[] data) {
+		 return true;
+	 }
+	
+	boolean validateReply(byte[] reply) {
+		if (reply[0] != '4')
+			return false;
+		if (reply[1] != '1')
+			return false;
+		if (reply[2] != pid.charAt(0))
+			return false;
+		if (reply[3] != pid.charAt(1))
+			return false;
+		
+		return true;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/eb267121/samples/connectors/src/main/java/quarks/samples/connectors/elm327/package-info.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/elm327/package-info.java
b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/package-info.java
new file mode 100644
index 0000000..e39904f
--- /dev/null
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/package-info.java
@@ -0,0 +1,27 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+/**
+ * OBD-II protocol sample using ELM327.
+ * 
+ * ELM327 devices allow connectivity to a vehicle's OBD-II information.
+ *
+ * @see <a href="https://en.wikipedia.org/wiki/OBD-II">OBD-II</a>
+ * @see <a href="https://en.wikipedia.org/wiki/ELM327">ELM327</a>
+ */
+package quarks.samples.connectors.elm327;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-quarks/blob/eb267121/samples/connectors/src/main/java/quarks/samples/connectors/elm327/runtime/CommandExecutor.java
----------------------------------------------------------------------
diff --git a/samples/connectors/src/main/java/quarks/samples/connectors/elm327/runtime/CommandExecutor.java
b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/runtime/CommandExecutor.java
new file mode 100644
index 0000000..f390b0c
--- /dev/null
+++ b/samples/connectors/src/main/java/quarks/samples/connectors/elm327/runtime/CommandExecutor.java
@@ -0,0 +1,118 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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 quarks.samples.connectors.elm327.runtime;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.google.gson.JsonObject;
+
+import quarks.samples.connectors.elm327.Cmd;
+import quarks.samples.connectors.elm327.Elm327Cmds;
+
+/**
+ * Runtime execution of ELM327 & OBD-II commands.
+ *
+ */
+public class CommandExecutor {
+
+    public static int[] binary(byte[] reply, int offset, int length) {
+        int[] binary = new int[length / 2];
+        for (int i = 0; i < binary.length; i++) {
+            int h = Character.digit(reply[offset++], 16);
+            int l = Character.digit(reply[offset++], 16);
+            binary[i] = ((h * 16) + l);
+        }
+        return binary;
+    }
+
+    public static void initialize(Cmd protocol, OutputStream out, InputStream in) {
+        try {
+
+            executeUntilOK(10, Elm327Cmds.INIT, out, in);
+            Thread.sleep(1000);
+
+            executeUntilOK(1, Elm327Cmds.ECHO_OFF, out, in);
+
+            executeUntilOK(1, protocol, out, in);
+            executeUntilOK(1, Elm327Cmds.SLOW_INIT, out, in);
+            Thread.sleep(1000);
+
+        } catch (Exception ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    private static boolean readUntilPrompt(InputStream in, ByteArrayOutputStream bytes) throws
IOException {
+        bytes.reset();
+        for (;;) {
+            int b = in.read();
+            if (b == -1)
+                return false;
+            if (b == ' ')
+                continue;
+            if (b == '\r')
+                continue;
+            if (b == '>')
+                return true;
+
+            bytes.write(b);
+        }
+    }
+
+    public static JsonObject executeUntilOK(int n, Cmd cmd, OutputStream out, InputStream
in) throws IOException {
+        try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(16)) {
+            for (int i = 0; i < n; i++) {
+                cmd.writeCmd(out);
+                out.flush();
+
+                if (!readUntilPrompt(in, bytes))
+                    continue;
+
+                byte[] reply = bytes.toByteArray();
+                JsonObject j = new JsonObject();
+                if (cmd.result(j, reply))
+                    return j;
+                break;
+            }
+        }
+        throw new IllegalStateException("Could not execute command:" + cmd);
+    }
+
+    public static JsonObject execute(Cmd cmd, OutputStream out, InputStream in) {
+        try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(16)) {
+            cmd.writeCmd(out);
+            out.flush();
+
+            JsonObject result = new JsonObject();
+            result.addProperty(Cmd.PID, cmd.id());
+            result.addProperty(Cmd.TS, System.currentTimeMillis());
+
+            readUntilPrompt(in, bytes);
+
+            cmd.result(result, bytes.toByteArray());
+
+            return result;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}


Mime
View raw message