summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanley Huang <stanleyhuangyc@gmail.com>2014-01-08 22:28:27 +1100
committerStanley Huang <stanleyhuangyc@gmail.com>2014-01-08 22:28:27 +1100
commit8f3ea96c48025f78e0f0447a38cced71587802e1 (patch)
treecbf0a3c7382c1f1cf3cf7b454d70c8536f3d82bb
parent876105a52a99b342f31a9319b9da7e7b3f123560 (diff)
download2021-arduino-obd-8f3ea96c48025f78e0f0447a38cced71587802e1.tar.gz
2021-arduino-obd-8f3ea96c48025f78e0f0447a38cced71587802e1.tar.bz2
2021-arduino-obd-8f3ea96c48025f78e0f0447a38cced71587802e1.zip
Update OBD library
-rw-r--r--libraries/OBD/OBD.cpp883
-rw-r--r--libraries/OBD/OBD.h298
2 files changed, 611 insertions, 570 deletions
diff --git a/libraries/OBD/OBD.cpp b/libraries/OBD/OBD.cpp
index c357da1..5f5d93a 100644
--- a/libraries/OBD/OBD.cpp
+++ b/libraries/OBD/OBD.cpp
@@ -1,431 +1,452 @@
-/*************************************************************************
-* Arduino Library for OBD-II UART Adapter
-* Distributed under GPL v2.0
-* Copyright (c) 2012~2013 Stanley Huang <stanleyhuangyc@gmail.com>
-* All rights reserved.
-*************************************************************************/
-
-#include <Arduino.h>
-#include <avr/pgmspace.h>
-#include "OBD.h"
-
-//#define DEBUG Serial
-//#define REDIRECT Serial
-
-#define MAX_CMD_LEN 6
-
-const char PROGMEM s_initcmd[][MAX_CMD_LEN] = {"ATZ\r","ATE0\r","ATL1\r","0902\r"};
-const char PROGMEM s_cmd_fmt[] = "%02X%02X 1\r";
-const char PROGMEM s_cmd_sleep[] = "atlp\r";
-#define STR_SEARCHING "SEARCHING..."
-
-unsigned int hex2uint16(const char *p)
-{
- char c = *p;
- unsigned int i = 0;
- for (char n = 0; c && n < 4; c = *(++p)) {
- if (c >= 'A' && c <= 'F') {
- c -= 7;
- } else if (c>='a' && c<='f') {
- c -= 39;
- } else if (c == ' ') {
- continue;
- } else if (c < '0' || c > '9') {
- break;
- }
- i = (i << 4) | (c & 0xF);
- n++;
- }
- return i;
-}
-
-unsigned char hex2uint8(const char *p)
-{
- unsigned char c1 = *p;
- unsigned char c2 = *(p + 1);
- if (c1 >= 'A' && c1 <= 'F')
- c1 -= 7;
- else if (c1 >='a' && c1 <= 'f')
- c1 -= 39;
- else if (c1 < '0' || c1 > '9')
- return 0;
-
- if (c2 >= 'A' && c2 <= 'F')
- c2 -= 7;
- else if (c2 >= 'a' && c2 <= 'f')
- c2 -= 39;
- else if (c2 < '0' || c2 > '9')
- return 0;
-
- return c1 << 4 | (c2 & 0xf);
-}
-
-/*************************************************************************
-* OBD-II UART Adapter
-*************************************************************************/
-#include <Wire.h>
-
-void COBD::sendQuery(unsigned char pid)
-{
- char cmd[8];
- sprintf_P(cmd, s_cmd_fmt, dataMode, pid);
-#ifdef DEBUG
- debugOutput(cmd);
-#endif
- write(cmd);
-}
-
-bool COBD::read(byte pid, int& result, bool passive)
-{
- // send a query command
- sendQuery(pid);
- // wait for reponse
- bool hasData;
- unsigned long tick = millis();
- do {
- dataIdleLoop();
- } while (!(hasData = available()) && millis() - tick < OBD_TIMEOUT_SHORT);
- if (!hasData) {
- errors++;
- return false;
- }
- // receive and parse the response
- return getResponseParsed(pid, result);
-}
-
-bool COBD::available()
-{
- return OBDUART.available();
-}
-
-char COBD::read()
-{
- char c = OBDUART.read();
-#ifdef REDIRECT
- REDIRECT.write(c);
-#endif
- return c;
-}
-
-void COBD::write(char* s)
-{
- OBDUART.write(s);
-}
-
-void COBD::write(char c)
-{
- OBDUART.write(c);
-}
-
-int COBD::normalizeData(byte pid, char* data)
-{
- int result;
- switch (pid) {
- case PID_RPM:
- result = getLargeValue(data) >> 2;
- break;
- case PID_FUEL_PRESSURE:
- result = getSmallValue(data) * 3;
- break;
- case PID_COOLANT_TEMP:
- case PID_INTAKE_TEMP:
- case PID_AMBIENT_TEMP:
- case PID_ENGINE_OIL_TEMP:
- result = getTemperatureValue(data);
- break;
- case PID_ABSOLUTE_ENGINE_LOAD:
- case PID_ETHANOL_PERCENTAGE:
- case PID_HYBRID_BATTERY_PERCENTAGE:
- result = getLargeValue(data) * 100 / 255; // %
- break;
- case PID_MAF_FLOW:
- result = getLargeValue(data) / 100;
- break;
- case PID_THROTTLE:
- case PID_ENGINE_LOAD:
- case PID_FUEL_LEVEL:
- result = getPercentageValue(data);
- break;
- case PID_TIMING_ADVANCE:
- result = (getSmallValue(data) - 128) >> 1;
- break;
- case PID_DISTANCE: // km
- case PID_RUNTIME: // second
- case PID_FUEL_RAIL_PRESSURE: // kPa
- case PID_ENGINE_REF_TORQUE: // Nm
- result = getLargeValue(data);
- break;
- case PID_CONTROL_MODULE_VOLTAGE: // V
- result = getLargeValue(data) / 1000;
- break;
- case PID_ENGINE_FUEL_RATE: // L/min
- result = getLargeValue(data) * 3;
- break;
- case PID_ENGINE_TORQUE_PERCENTAGE: // %
- result = (int)getSmallValue(data) - 125;
- break;
- default:
- result = getSmallValue(data);
- }
- return result;
-}
-
-char* COBD::getResponse(byte& pid, char* buffer)
-{
- byte n = receive(buffer);
- if (n > 6) {
- char *p = buffer;
- while ((p = strstr(p, "41 "))) {
- p += 3;
- byte curpid = hex2uint8(p);
- if (pid == 0) pid = curpid;
- if (curpid == pid) {
- errors = 0;
- p += 2;
- if (*p == ' ')
- return p + 1;
- }
- };
- }
- return 0;
-}
-
-bool COBD::getResponseParsed(byte& pid, int& result)
-{
- char buffer[OBD_RECV_BUF_SIZE];
- char* data = getResponse(pid, buffer);
- if (!data) {
- // try recover next time
- //write('\r');
- return false;
- }
- result = normalizeData(pid, data);
- return true;
-}
-
-void COBD::sleep(int seconds)
-{
- char cmd[MAX_CMD_LEN];
- strcpy_P(cmd, s_cmd_sleep);
- write(cmd);
- if (seconds) {
- delay((unsigned long)seconds << 10);
- write('\r');
- }
-}
-
-bool COBD::isValidPID(byte pid)
-{
- if (pid >= 0x7f)
- return false;
- pid--;
- byte i = pid >> 3;
- byte b = 0x80 >> (pid & 0x7);
- return pidmap[i] & b;
-}
-
-void COBD::begin()
-{
- OBDUART.begin(OBD_SERIAL_BAUDRATE);
-}
-
-byte COBD::receive(char* buffer)
-{
- unsigned long startTime = millis();
- unsigned char n = 0;
- int timeout = OBD_TIMEOUT_SHORT;
- bool prompted = false;
-
- buffer[0] = 0;
- for (;;) {
- if (available()) {
- char c = read();
- if (n > 2 && c == '>') {
- // prompt char received
- prompted = true;
- } else if (n < OBD_RECV_BUF_SIZE - 1) {
- buffer[n++] = c;
- buffer[n] = 0;
- if (strstr(buffer, STR_SEARCHING)) {
- strcpy(buffer, buffer + sizeof(STR_SEARCHING));
- n -= sizeof(STR_SEARCHING);
- timeout = OBD_TIMEOUT_LONG;
- }
- }
- } else if (prompted) {
- break;
- } else {
- if (millis() - startTime > timeout) {
- // timeout
- return 0;
- }
- dataIdleLoop();
- }
- }
-
- return n;
-}
-
-bool COBD::init(bool passive)
-{
- unsigned long currentMillis;
- char buffer[OBD_RECV_BUF_SIZE];
-
- m_state = OBD_CONNECTING;
-
- write('\r');
- delay(100);
- while (available()) read();
-
- for (unsigned char i = 0; i < sizeof(s_initcmd) / sizeof(s_initcmd[0]); i++) {
- if (!passive) {
- char cmd[MAX_CMD_LEN];
- strcpy_P(cmd, s_initcmd[i]);
-#ifdef DEBUG
- debugOutput(cmd);
-#endif
- write(cmd);
- }
- if (receive(buffer) == 0) {
- return false;
- }
- }
- while (available()) read();
-
- // load pid map
- memset(pidmap, 0, sizeof(pidmap));
- for (byte i = 0; i < 4; i++) {
- byte pid = i * 0x20;
- sendQuery(pid);
- char* data = getResponse(pid, buffer);
- if (!data) break;
- data--;
- for (byte n = 0; n < 4; n++) {
- if (data[n * 3] != ' ')
- break;
- pidmap[i * 4 + n] = hex2uint8(data + n * 3 + 1);
- }
- }
- while (available()) read();
-
- m_state = OBD_CONNECTED;
- errors = 0;
- return true;
-}
-
-#ifdef DEBUG
-void COBD::debugOutput(const char *s)
-{
- DEBUG.print('[');
- DEBUG.print(millis());
- DEBUG.print(']');
- DEBUG.print(s);
-}
-#endif
-
-/*************************************************************************
-* OBD-II I2C Adapter
-*************************************************************************/
-
-void COBDI2C::begin(byte addr)
-{
- m_addr = addr;
- Wire.begin();
-}
-
-bool COBDI2C::init()
-{
- m_state = OBD_CONNECTING;
- sendCommand(CMD_QUERY_STATUS);
-
- char recvbuf[MAX_PAYLOAD_SIZE];
- for (byte n = 0; n < 3; n++) {
- memset(recvbuf, 0, sizeof(recvbuf));
- receive(recvbuf);
- if (!memcmp(recvbuf, "OBD ", 4))
- break;
- }
- if (recvbuf[4] == 'Y') {
- memcpy(pidmap, recvbuf + 16, sizeof(pidmap));
- m_state = OBD_CONNECTED;
- return true;
- } else {
- m_state = OBD_DISCONNECTED;
- return false;
- }
-}
-
-bool COBDI2C::read(byte pid, int& result, bool passive)
-{
- uint32_t t = millis();
- sendQuery(pid);
- dataIdleLoop();
- return getResponseParsed(pid, result);
-}
-
-void COBDI2C::write(char* s)
-{
- COMMAND_BLOCK cmdblock = {millis(), CMD_SEND_COMMAND};
- Wire.beginTransmission(m_addr);
- Wire.write((byte*)&cmdblock, sizeof(cmdblock));
- Wire.write(s);
- Wire.endTransmission();
-}
-
-bool COBDI2C::sendCommand(byte cmd, uint8_t data, byte* payload, byte payloadBytes)
-{
- COMMAND_BLOCK cmdblock = {millis(), cmd, data};
- Wire.beginTransmission(m_addr);
- bool success = Wire.write((byte*)&cmdblock, sizeof(COMMAND_BLOCK)) == sizeof(COMMAND_BLOCK);
- if (payload) Wire.write(payload, payloadBytes);
- Wire.endTransmission();
- return success;
-}
-
-byte COBDI2C::receive(char* buffer)
-{
- uint32_t start = millis();
- byte offset = 0;
- do {
- Wire.requestFrom((byte)m_addr, (byte)MAX_PAYLOAD_SIZE, (byte)1);
-
- bool hasEnd = false;
- for (byte i = 0; i < MAX_PAYLOAD_SIZE; i++) {
- if ((buffer[offset + i] = Wire.read()) == 0)
- hasEnd = true;
- }
-
- if (buffer[0] == 0) {
- // data not ready
- dataIdleLoop();
- continue;
- }
-
- offset += MAX_PAYLOAD_SIZE;
- if (!hasEnd) {
- continue;
- }
-
- return offset;
- } while(millis() - start < OBD_TIMEOUT_LONG);
- return 0;
-}
-
-bool COBDI2C::btInit(uint16_t baudrate)
-{
- return sendCommand(CMD_UART_BEGIN, baudrate / 1200);
-}
-
-bool COBDI2C::btSend(byte* data, byte length)
-{
- return sendCommand(CMD_UART_SEND, 0, data, length);
-}
-
-bool COBDI2C::btReceive(byte* buffer, byte bufsize)
-{
- if (!sendCommand(CMD_UART_RECV, bufsize)) return false;
- memset(buffer, 0, MAX_PAYLOAD_SIZE);
- Wire.requestFrom((byte)m_addr, (byte)MAX_PAYLOAD_SIZE, (byte)1);
- Wire.readBytes((char*)buffer, MAX_PAYLOAD_SIZE);
- return true;
-}
+/*************************************************************************
+* Arduino Library for OBD-II UART/I2C Adapter
+* Distributed under GPL v2.0
+* Visit http://arduinodev.com for more information
+* (C)2012-2014 Stanley Huang <stanleyhuangyc@gmail.com>
+*************************************************************************/
+
+#include <Arduino.h>
+#include <avr/pgmspace.h>
+#include "OBD.h"
+
+//#define DEBUG Serial
+//#define REDIRECT Serial
+
+#define MAX_CMD_LEN 6
+
+const char PROGMEM s_initcmd[][MAX_CMD_LEN] = {"ATZ\r","ATE0\r","ATL1\r","0902\r"};
+const char PROGMEM s_cmd_fmt[] = "%02X%02X 1\r";
+const char PROGMEM s_cmd_sleep[] = "atlp\r";
+#define STR_SEARCHING "SEARCHING..."
+
+unsigned int hex2uint16(const char *p)
+{
+ char c = *p;
+ unsigned int i = 0;
+ for (char n = 0; c && n < 4; c = *(++p)) {
+ if (c >= 'A' && c <= 'F') {
+ c -= 7;
+ } else if (c>='a' && c<='f') {
+ c -= 39;
+ } else if (c == ' ') {
+ continue;
+ } else if (c < '0' || c > '9') {
+ break;
+ }
+ i = (i << 4) | (c & 0xF);
+ n++;
+ }
+ return i;
+}
+
+unsigned char hex2uint8(const char *p)
+{
+ unsigned char c1 = *p;
+ unsigned char c2 = *(p + 1);
+ if (c1 >= 'A' && c1 <= 'F')
+ c1 -= 7;
+ else if (c1 >='a' && c1 <= 'f')
+ c1 -= 39;
+ else if (c1 < '0' || c1 > '9')
+ return 0;
+
+ if (c2 >= 'A' && c2 <= 'F')
+ c2 -= 7;
+ else if (c2 >= 'a' && c2 <= 'f')
+ c2 -= 39;
+ else if (c2 < '0' || c2 > '9')
+ return 0;
+
+ return c1 << 4 | (c2 & 0xf);
+}
+
+/*************************************************************************
+* OBD-II UART Adapter
+*************************************************************************/
+#include <Wire.h>
+
+void COBD::sendQuery(unsigned char pid)
+{
+ char cmd[8];
+ sprintf_P(cmd, s_cmd_fmt, dataMode, pid);
+#ifdef DEBUG
+ debugOutput(cmd);
+#endif
+ write(cmd);
+}
+
+bool COBD::read(byte pid, int& result, bool passive)
+{
+ // send a query command
+ sendQuery(pid);
+ // wait for reponse
+ bool hasData;
+ unsigned long tick = millis();
+ do {
+ dataIdleLoop();
+ } while (!(hasData = available()) && millis() - tick < OBD_TIMEOUT_SHORT);
+ if (!hasData) {
+ errors++;
+ return false;
+ }
+ // receive and parse the response
+ return getResponseParsed(pid, result);
+}
+
+bool COBD::available()
+{
+ return OBDUART.available();
+}
+
+char COBD::read()
+{
+ char c = OBDUART.read();
+#ifdef REDIRECT
+ REDIRECT.write(c);
+#endif
+ return c;
+}
+
+void COBD::write(char* s)
+{
+ OBDUART.write(s);
+}
+
+void COBD::write(char c)
+{
+ OBDUART.write(c);
+}
+
+int COBD::normalizeData(byte pid, char* data)
+{
+ int result;
+ switch (pid) {
+ case PID_RPM:
+ result = getLargeValue(data) >> 2;
+ break;
+ case PID_FUEL_PRESSURE:
+ result = getSmallValue(data) * 3;
+ break;
+ case PID_COOLANT_TEMP:
+ case PID_INTAKE_TEMP:
+ case PID_AMBIENT_TEMP:
+ case PID_ENGINE_OIL_TEMP:
+ result = getTemperatureValue(data);
+ break;
+ case PID_ABSOLUTE_ENGINE_LOAD:
+ case PID_ETHANOL_PERCENTAGE:
+ case PID_HYBRID_BATTERY_PERCENTAGE:
+ result = getLargeValue(data) * 100 / 255; // %
+ break;
+ case PID_MAF_FLOW:
+ result = getLargeValue(data) / 100;
+ break;
+ case PID_THROTTLE:
+ case PID_ENGINE_LOAD:
+ case PID_FUEL_LEVEL:
+ result = getPercentageValue(data);
+ break;
+ case PID_TIMING_ADVANCE:
+ result = (getSmallValue(data) - 128) >> 1;
+ break;
+ case PID_DISTANCE: // km
+ case PID_RUNTIME: // second
+ case PID_FUEL_RAIL_PRESSURE: // kPa
+ case PID_ENGINE_REF_TORQUE: // Nm
+ result = getLargeValue(data);
+ break;
+ case PID_CONTROL_MODULE_VOLTAGE: // V
+ result = getLargeValue(data) / 1000;
+ break;
+ case PID_ENGINE_FUEL_RATE: // L/min
+ result = getLargeValue(data) * 3;
+ break;
+ case PID_ENGINE_TORQUE_PERCENTAGE: // %
+ result = (int)getSmallValue(data) - 125;
+ break;
+ default:
+ result = getSmallValue(data);
+ }
+ return result;
+}
+
+char* COBD::getResponse(byte& pid, char* buffer)
+{
+ byte n = receive(buffer);
+ if (n > 6) {
+ char *p = buffer;
+ while ((p = strstr(p, "41 "))) {
+ p += 3;
+ byte curpid = hex2uint8(p);
+ if (pid == 0) pid = curpid;
+ if (curpid == pid) {
+ errors = 0;
+ p += 2;
+ if (*p == ' ')
+ return p + 1;
+ }
+ };
+ }
+ return 0;
+}
+
+bool COBD::getResponseParsed(byte& pid, int& result)
+{
+ char buffer[OBD_RECV_BUF_SIZE];
+ char* data = getResponse(pid, buffer);
+ if (!data) {
+ // try recover next time
+ //write('\r');
+ return false;
+ }
+ result = normalizeData(pid, data);
+ return true;
+}
+
+void COBD::sleep(int seconds)
+{
+ char cmd[MAX_CMD_LEN];
+ strcpy_P(cmd, s_cmd_sleep);
+ write(cmd);
+ if (seconds) {
+ delay((unsigned long)seconds << 10);
+ write('\r');
+ }
+}
+
+bool COBD::isValidPID(byte pid)
+{
+ if (pid >= 0x7f)
+ return false;
+ pid--;
+ byte i = pid >> 3;
+ byte b = 0x80 >> (pid & 0x7);
+ return pidmap[i] & b;
+}
+
+void COBD::begin()
+{
+ OBDUART.begin(OBD_SERIAL_BAUDRATE);
+}
+
+byte COBD::receive(char* buffer)
+{
+ unsigned long startTime = millis();
+ unsigned char n = 0;
+ int timeout = OBD_TIMEOUT_SHORT;
+ bool prompted = false;
+
+ buffer[0] = 0;
+ for (;;) {
+ if (available()) {
+ char c = read();
+ if (n > 2 && c == '>') {
+ // prompt char received
+ prompted = true;
+ } else if (n < OBD_RECV_BUF_SIZE - 1) {
+ buffer[n++] = c;
+ buffer[n] = 0;
+ if (strstr(buffer, STR_SEARCHING)) {
+ strcpy(buffer, buffer + sizeof(STR_SEARCHING));
+ n -= sizeof(STR_SEARCHING);
+ timeout = OBD_TIMEOUT_LONG;
+ }
+ }
+ } else if (prompted) {
+ break;
+ } else {
+ if (millis() - startTime > timeout) {
+ // timeout
+ return 0;
+ }
+ dataIdleLoop();
+ }
+ }
+
+ return n;
+}
+
+bool COBD::init(bool passive)
+{
+ unsigned long currentMillis;
+ char buffer[OBD_RECV_BUF_SIZE];
+
+ m_state = OBD_CONNECTING;
+
+ write('\r');
+ delay(100);
+ while (available()) read();
+
+ for (unsigned char i = 0; i < sizeof(s_initcmd) / sizeof(s_initcmd[0]); i++) {
+ if (!passive) {
+ char cmd[MAX_CMD_LEN];
+ strcpy_P(cmd, s_initcmd[i]);
+#ifdef DEBUG
+ debugOutput(cmd);
+#endif
+ write(cmd);
+ }
+ if (receive(buffer) == 0) {
+ return false;
+ }
+ }
+ while (available()) read();
+
+ // load pid map
+ memset(pidmap, 0, sizeof(pidmap));
+ for (byte i = 0; i < 4; i++) {
+ byte pid = i * 0x20;
+ sendQuery(pid);
+ char* data = getResponse(pid, buffer);
+ if (!data) break;
+ data--;
+ for (byte n = 0; n < 4; n++) {
+ if (data[n * 3] != ' ')
+ break;
+ pidmap[i * 4 + n] = hex2uint8(data + n * 3 + 1);
+ }
+ }
+ while (available()) read();
+
+ m_state = OBD_CONNECTED;
+ errors = 0;
+ return true;
+}
+
+#ifdef DEBUG
+void COBD::debugOutput(const char *s)
+{
+ DEBUG.print('[');
+ DEBUG.print(millis());
+ DEBUG.print(']');
+ DEBUG.print(s);
+}
+#endif
+
+/*************************************************************************
+* OBD-II I2C Adapter
+*************************************************************************/
+
+void COBDI2C::begin(byte addr)
+{
+ m_addr = addr;
+ Wire.begin();
+}
+
+bool COBDI2C::init()
+{
+ m_state = OBD_CONNECTING;
+ sendCommand(CMD_QUERY_STATUS);
+
+ char recvbuf[MAX_PAYLOAD_SIZE];
+ for (byte n = 0; n < 3; n++) {
+ memset(recvbuf, 0, sizeof(recvbuf));
+ receive(recvbuf);
+ if (!memcmp(recvbuf, "OBD ", 4))
+ break;
+ }
+ if (recvbuf[4] == 'Y') {
+ memcpy(pidmap, recvbuf + 16, sizeof(pidmap));
+ m_state = OBD_CONNECTED;
+ return true;
+ } else {
+ m_state = OBD_DISCONNECTED;
+ return false;
+ }
+}
+
+bool COBDI2C::read(byte pid, int& result, bool passive)
+{
+ uint32_t t = millis();
+ sendQuery(pid);
+ dataIdleLoop();
+ return getResponseParsed(pid, result);
+}
+
+void COBDI2C::write(char* s)
+{
+ COMMAND_BLOCK cmdblock = {millis(), CMD_SEND_COMMAND};
+ Wire.beginTransmission(m_addr);
+ Wire.write((byte*)&cmdblock, sizeof(cmdblock));
+ Wire.write(s);
+ Wire.endTransmission();
+}
+
+bool COBDI2C::sendCommand(byte cmd, uint8_t data, byte* payload, byte payloadBytes)
+{
+ COMMAND_BLOCK cmdblock = {millis(), cmd, data};
+ Wire.beginTransmission(m_addr);
+ bool success = Wire.write((byte*)&cmdblock, sizeof(COMMAND_BLOCK)) == sizeof(COMMAND_BLOCK);
+ if (payload) Wire.write(payload, payloadBytes);
+ Wire.endTransmission();
+ return success;
+}
+
+byte COBDI2C::receive(char* buffer)
+{
+ uint32_t start = millis();
+ byte offset = 0;
+ do {
+ Wire.requestFrom((byte)m_addr, (byte)MAX_PAYLOAD_SIZE, (byte)1);
+
+ bool hasEnd = false;
+ for (byte i = 0; i < MAX_PAYLOAD_SIZE; i++) {
+ if ((buffer[offset + i] = Wire.read()) == 0)
+ hasEnd = true;
+ }
+
+ if (buffer[0] == 0) {
+ // data not ready
+ dataIdleLoop();
+ continue;
+ }
+
+ offset += MAX_PAYLOAD_SIZE;
+ if (!hasEnd) {
+ continue;
+ }
+
+ return offset;
+ } while(millis() - start < OBD_TIMEOUT_LONG);
+ return 0;
+}
+
+bool COBDI2C::btInit(uint16_t baudrate)
+{
+ return sendCommand(CMD_UART_BEGIN, baudrate / 1200);
+}
+
+bool COBDI2C::btSend(byte* data, byte length)
+{
+ return sendCommand(CMD_UART_SEND, 0, data, length);
+}
+
+bool COBDI2C::btReceive(byte* buffer, byte bufsize)
+{
+ if (!sendCommand(CMD_UART_RECV, bufsize)) return false;
+ memset(buffer, 0, MAX_PAYLOAD_SIZE);
+ delay(10);
+ Wire.requestFrom((byte)m_addr, (byte)MAX_PAYLOAD_SIZE, (byte)1);
+ Wire.readBytes((char*)buffer, MAX_PAYLOAD_SIZE);
+ return true;
+}
+
+bool COBDI2C::gpsQuery(GPS_DATA* gpsdata)
+{
+ if (!sendCommand(CMD_GPS_QUERY, 0)) return false;
+ delay(1);
+ Wire.requestFrom((byte)m_addr, (byte)MAX_PAYLOAD_SIZE, (byte)1);
+ Wire.readBytes((char*)gpsdata, MAX_PAYLOAD_SIZE);
+ return true;
+
+}
+
+void COBDI2C::gpsStart(uint32_t baudrate, const char* cmds)
+{
+ sendCommand(CMD_GPS_START, baudrate / 1200, (byte*)cmds, strlen(cmds));
+}
+
+void COBDI2C::gpsStop()
+{
+ sendCommand(CMD_GPS_STOP);
+}
diff --git a/libraries/OBD/OBD.h b/libraries/OBD/OBD.h
index 82e1c1a..3ecd6cc 100644
--- a/libraries/OBD/OBD.h
+++ b/libraries/OBD/OBD.h
@@ -1,139 +1,159 @@
-/*************************************************************************
-* Arduino Library for OBD-II UART Adapter
-* Distributed under GPL v2.0
-* Copyright (c) 2012~2013 Stanley Huang <stanleyhuangyc@gmail.com>
-* All rights reserved.
-*************************************************************************/
-
-#define OBD_TIMEOUT_SHORT 2000 /* ms */
-#define OBD_TIMEOUT_LONG 7000 /* ms */
-#define OBD_SERIAL_BAUDRATE 38400
-#define OBD_RECV_BUF_SIZE 80
-
-#ifndef OBDUART
-#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega644P__)
-#define OBDUART Serial1
-#else
-#define OBDUART Serial
-#endif
-#endif
-
-// mode 0 pids
-#define PID_ENGINE_LOAD 0x04
-#define PID_COOLANT_TEMP 0x05
-#define PID_FUEL_PRESSURE 0x0A
-#define PID_INTAKE_MAP 0x0B
-#define PID_RPM 0x0C
-#define PID_SPEED 0x0D
-#define PID_TIMING_ADVANCE 0x0E
-#define PID_INTAKE_TEMP 0x0F
-#define PID_MAF_FLOW 0x10
-#define PID_THROTTLE 0x11
-#define PID_RUNTIME 0x1F
-#define PID_FUEL_LEVEL 0x2F
-#define PID_DISTANCE 0x31
-#define PID_BAROMETRIC 0x33
-#define PID_CONTROL_MODULE_VOLTAGE 0x42
-#define PID_ABSOLUTE_ENGINE_LOAD 0x43
-#define PID_AMBIENT_TEMP 0x46
-#define PID_ETHANOL_PERCENTAGE 0x52
-#define PID_FUEL_RAIL_PRESSURE 0x59
-#define PID_HYBRID_BATTERY_PERCENTAGE 0x5B
-#define PID_ENGINE_OIL_TEMP 0x5C
-#define PID_ENGINE_FUEL_RATE 0x5E
-#define PID_ENGINE_TORQUE_PERCENTAGE 0x62
-#define PID_ENGINE_REF_TORQUE 0x63
-
-// states
-#define OBD_DISCONNECTED 0
-#define OBD_CONNECTING 1
-#define OBD_CONNECTED 2
-
-unsigned int hex2uint16(const char *p);
-unsigned char hex2uint8(const char *p);
-
-class COBD
-{
-public:
- COBD():dataMode(1),errors(0),m_state(OBD_DISCONNECTED) {}
- virtual void begin();
- virtual bool init(bool passive = false);
- virtual bool read(byte pid, int& result, bool passive = false);
- virtual void sleep(int seconds);
- // Query and GetResponse for advanced usage only
- virtual void sendQuery(byte pid);
- bool isValidPID(byte pid);
- byte getState() { return m_state; }
- byte dataMode;
- byte errors;
- byte pidmap[4 * 4];
- byte vin[17];
-protected:
- virtual char* getResponse(byte& pid, char* buffer);
- virtual bool getResponseParsed(byte& pid, int& result);
- virtual byte receive(char* buffer);
- virtual bool available();
- virtual char read();
- virtual void write(char* s);
- virtual void write(char c);
- virtual void dataIdleLoop() {}
- void debugOutput(const char* s);
- int normalizeData(byte pid, char* data);
- byte m_state;
-private:
- virtual uint8_t getPercentageValue(char* data)
- {
- return (uint16_t)hex2uint8(data) * 100 / 255;
- }
- virtual uint16_t getLargeValue(char* data)
- {
- return hex2uint16(data);
- }
- virtual uint8_t getSmallValue(char* data)
- {
- return hex2uint8(data);
- }
- virtual int16_t getTemperatureValue(char* data)
- {
- return (int)hex2uint8(data) - 40;
- }
-};
-
-#define I2C_ADDR 0x62
-
-#define MAX_PAYLOAD_SIZE 32
-
-#define CMD_QUERY_STATUS 0x10
-#define CMD_SEND_COMMAND 0x11
-#define CMD_QUERY_DATA 0x12
-#define CMD_UART_BEGIN 0x13
-#define CMD_UART_SEND 0x14
-#define CMD_UART_RECV 0x15
-
-typedef struct {
- uint32_t time;
- uint16_t pid;
- float value;
-} PID_INFO;
-
-typedef struct {
- uint16_t time;
- uint8_t message;
- uint8_t data;
-} COMMAND_BLOCK;
-
-class COBDI2C : public COBD {
-public:
- void begin(byte addr = I2C_ADDR);
- bool init();
- bool read(byte pid, int& result, bool passive = false);
- void write(char* s);
- // Bluetooth communication API
- bool btInit(uint16_t baudrate = 9600);
- bool btSend(byte* data, byte length);
- bool btReceive(byte* buffer, byte bufsize);
-private:
- bool sendCommand(byte cmd, uint8_t data = 0, byte* payload = 0, byte payloadBytes = 0);
- byte receive(char* buffer);
- byte m_addr;
-};
+/*************************************************************************
+* Arduino Library for OBD-II UART/I2C Adapter
+* Distributed under GPL v2.0
+* Visit http://arduinodev.com for more information
+* (C)2012-2014 Stanley Huang <stanleyhuangyc@gmail.com>
+*************************************************************************/
+
+#define OBD_TIMEOUT_SHORT 2000 /* ms */
+#define OBD_TIMEOUT_LONG 7000 /* ms */
+#define OBD_SERIAL_BAUDRATE 38400
+#define OBD_RECV_BUF_SIZE 80
+
+#ifndef OBDUART
+#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega644P__)
+#define OBDUART Serial1
+#else
+#define OBDUART Serial
+#endif
+#endif
+
+// Mode 1 PIDs
+#define PID_ENGINE_LOAD 0x04
+#define PID_COOLANT_TEMP 0x05
+#define PID_FUEL_PRESSURE 0x0A
+#define PID_INTAKE_MAP 0x0B
+#define PID_RPM 0x0C
+#define PID_SPEED 0x0D
+#define PID_TIMING_ADVANCE 0x0E
+#define PID_INTAKE_TEMP 0x0F
+#define PID_MAF_FLOW 0x10
+#define PID_THROTTLE 0x11
+#define PID_RUNTIME 0x1F
+#define PID_FUEL_LEVEL 0x2F
+#define PID_DISTANCE 0x31
+#define PID_BAROMETRIC 0x33
+#define PID_CONTROL_MODULE_VOLTAGE 0x42
+#define PID_ABSOLUTE_ENGINE_LOAD 0x43
+#define PID_AMBIENT_TEMP 0x46
+#define PID_ETHANOL_PERCENTAGE 0x52
+#define PID_FUEL_RAIL_PRESSURE 0x59
+#define PID_HYBRID_BATTERY_PERCENTAGE 0x5B
+#define PID_ENGINE_OIL_TEMP 0x5C
+#define PID_ENGINE_FUEL_RATE 0x5E
+#define PID_ENGINE_TORQUE_PERCENTAGE 0x62
+#define PID_ENGINE_REF_TORQUE 0x63
+
+// states
+#define OBD_DISCONNECTED 0
+#define OBD_CONNECTING 1
+#define OBD_CONNECTED 2
+
+unsigned int hex2uint16(const char *p);
+unsigned char hex2uint8(const char *p);
+
+class COBD
+{
+public:
+ COBD():dataMode(1),errors(0),m_state(OBD_DISCONNECTED) {}
+ virtual void begin();
+ virtual bool init(bool passive = false);
+ virtual bool read(byte pid, int& result, bool passive = false);
+ virtual void sleep(int seconds);
+ // Query and GetResponse for advanced usage only
+ virtual void sendQuery(byte pid);
+ bool isValidPID(byte pid);
+ byte getState() { return m_state; }
+ byte dataMode;
+ byte errors;
+ byte pidmap[4 * 4];
+ byte vin[17];
+protected:
+ virtual char* getResponse(byte& pid, char* buffer);
+ virtual bool getResponseParsed(byte& pid, int& result);
+ virtual byte receive(char* buffer);
+ virtual bool available();
+ virtual char read();
+ virtual void write(char* s);
+ virtual void write(char c);
+ virtual void dataIdleLoop() {}
+ void debugOutput(const char* s);
+ int normalizeData(byte pid, char* data);
+ byte m_state;
+private:
+ virtual uint8_t getPercentageValue(char* data)
+ {
+ return (uint16_t)hex2uint8(data) * 100 / 255;
+ }
+ virtual uint16_t getLargeValue(char* data)
+ {
+ return hex2uint16(data);
+ }
+ virtual uint8_t getSmallValue(char* data)
+ {
+ return hex2uint8(data);
+ }
+ virtual int16_t getTemperatureValue(char* data)
+ {
+ return (int)hex2uint8(data) - 40;
+ }
+};
+
+#define I2C_ADDR 0x62
+
+#define MAX_PAYLOAD_SIZE 32
+
+#define CMD_QUERY_STATUS 0x10
+#define CMD_SEND_COMMAND 0x11
+#define CMD_QUERY_DATA 0x12
+#define CMD_UART_BEGIN 0x13
+#define CMD_UART_SEND 0x14
+#define CMD_UART_RECV 0x15
+#define CMD_GPS_START 0x20
+#define CMD_GPS_STOP 0x21
+#define CMD_GPS_QUERY 0x22
+
+typedef struct {
+ uint32_t time;
+ uint16_t pid;
+ float value;
+} PID_INFO;
+
+typedef struct {
+ uint16_t time;
+ uint8_t message;
+ uint8_t data;
+} COMMAND_BLOCK;
+
+typedef struct {
+ uint32_t time;
+ uint32_t date;
+ float lat;
+ float lon;
+ float speed;
+ float alt;
+ uint8_t sat;
+ uint8_t state;
+ uint16_t age;
+ uint8_t reserved[4];
+} GPS_DATA;
+
+class COBDI2C : public COBD {
+public:
+ void begin(byte addr = I2C_ADDR);
+ bool init();
+ bool read(byte pid, int& result, bool passive = false);
+ void write(char* s);
+ // Bluetooth communication API
+ bool btInit(uint16_t baudrate = 9600);
+ bool btSend(byte* data, byte length);
+ bool btReceive(byte* buffer, byte bufsize);
+ // GPS API
+ bool gpsQuery(GPS_DATA* gpsdata);
+ void gpsStart(uint32_t baudrate = 38400, const char* cmds = 0);
+ void gpsStop();
+private:
+ bool sendCommand(byte cmd, uint8_t data = 0, byte* payload = 0, byte payloadBytes = 0);
+ byte receive(char* buffer);
+ byte m_addr;
+};