From e79cda0d48877f5f0404791a781e82c4e6e6f456 Mon Sep 17 00:00:00 2001
From: Stanley Huang <stanleyhuangyc@gmail.com>
Date: Thu, 25 Jan 2018 15:04:07 +1100
Subject: Improve VIN reading

---
 libraries/OBD/OBD.cpp | 40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

(limited to 'libraries')

diff --git a/libraries/OBD/OBD.cpp b/libraries/OBD/OBD.cpp
index 8dbdd29..92b9bdf 100644
--- a/libraries/OBD/OBD.cpp
+++ b/libraries/OBD/OBD.cpp
@@ -298,21 +298,31 @@ float COBD::getVoltage()
 
 bool COBD::getVIN(char* buffer, byte bufsize)
 {
-	if (sendCommand("0902\r", buffer, bufsize)) {
-        char *p = strstr(buffer, "0: 49 02");
-        if (p) {
-            char *q = buffer;
-            p += 10;
-            do {
-                for (++p; *p == ' '; p += 3) {
-                    if (*q = hex2uint8(p + 1)) q++;
-                }
-                p = strchr(p, ':');
-            } while(p);
-            *q = 0;
-            return true;
-        }
-    }
+	for (byte n = 0; n < 5; n++) {
+		if (sendCommand("0902\r", buffer, bufsize)) {
+			int len = hex2uint16(buffer);
+			char *p = strstr_P(buffer + 4, PSTR("0: 49 02 01"));
+			if (p) {
+				char *q = buffer;
+				p += 11; // skip the header
+				do {
+					while (*(++p) == ' ');
+					for (;;) {
+						*(q++) = hex2uint8(p);
+						while (*p && *p != ' ') p++;
+						while (*p == ' ') p++;
+						if (!*p || *p == '\r') break;
+					}
+					p = strchr(p, ':');
+				} while(p);
+				*q = 0;
+				if (q - buffer == len - 3) {
+					return true;
+				}
+			}
+		}
+		delay(100);
+	}
     return false;
 }
 
-- 
cgit v1.2.3


From bd86ac57fe9fa492e7e40e09d81de31bed1f449c Mon Sep 17 00:00:00 2001
From: Stanley Huang <stanleyhuangyc@gmail.com>
Date: Tue, 30 Jan 2018 22:37:56 +1100
Subject: Add support for Freematics OBD-II UART Adapter V2.1

---
 libraries/OBD2UART/OBD2UART.cpp                    | 244 +++++++++++++++------
 libraries/OBD2UART/OBD2UART.h                      |  74 +++----
 .../examples/obd_uart_test/obd_uart_test.ino       |  81 ++++---
 .../examples/orientation_demo/orientation_demo.ino |  98 +++++++++
 .../examples/rpm_led_uart/rpm_led_uart.ino         |   9 +-
 libraries/OBD2UART/keywords.txt                    |  29 +++
 libraries/OBD2UART/library.properties              |   9 +
 7 files changed, 400 insertions(+), 144 deletions(-)
 create mode 100644 libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino
 create mode 100644 libraries/OBD2UART/keywords.txt
 create mode 100644 libraries/OBD2UART/library.properties

(limited to 'libraries')

diff --git a/libraries/OBD2UART/OBD2UART.cpp b/libraries/OBD2UART/OBD2UART.cpp
index 0cb72f1..8406251 100644
--- a/libraries/OBD2UART/OBD2UART.cpp
+++ b/libraries/OBD2UART/OBD2UART.cpp
@@ -17,12 +17,12 @@ uint16_t hex2uint16(const char *p)
 {
 	char c = *p;
 	uint16_t i = 0;
-	for (char n = 0; c && n < 4; c = *(++p)) {
+	for (uint8_t 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 == ' ') {
+        } else if (c == ' ' && n == 2) {
             continue;
         } else if (c < '0' || c > '9') {
 			break;
@@ -44,7 +44,9 @@ byte hex2uint8(const char *p)
 	else if (c1 < '0' || c1 > '9')
 		return 0;
 
-	if (c2 >= 'A' && c2 <= 'F')
+	if (c2 == 0)
+		return (c1 & 0xf);
+	else if (c2 >= 'A' && c2 <= 'F')
 		c2 -= 7;
 	else if (c2 >= 'a' && c2 <= 'f')
 	    c2 -= 39;
@@ -61,24 +63,15 @@ byte hex2uint8(const char *p)
 byte COBD::sendCommand(const char* cmd, char* buf, byte bufsize, int timeout)
 {
 	write(cmd);
-	dataIdleLoop();
+	idleTasks();
 	return receive(buf, bufsize, timeout);
 }
 
-void COBD::sendQuery(byte pid)
+bool COBD::readPID(byte pid, int& result)
 {
 	char cmd[8];
 	sprintf(cmd, "%02X%02X\r", dataMode, pid);
-#ifdef DEBUG
-	debugOutput(cmd);
-#endif
 	write(cmd);
-}
-
-bool COBD::readPID(byte pid, int& result)
-{
-	// send a query command
-	sendQuery(pid);
 	// receive and parse the response
 	return getResult(pid, result);
 }
@@ -107,7 +100,7 @@ byte COBD::readDTC(uint16_t codes[], byte maxCodes)
 		sprintf_P(buffer, n == 0 ? PSTR("03\r") : PSTR("03%02X\r"), n);
 		write(buffer);
 		if (receive(buffer, sizeof(buffer)) > 0) {
-			if (!strstr(buffer, "NO DATA")) {
+			if (!strstr_P(buffer, PSTR("NO DATA"))) {
 				char *p = strstr(buffer, "43");
 				if (p) {
 					while (codesRead < maxCodes && *p) {
@@ -300,20 +293,30 @@ float COBD::getVoltage()
 
 bool COBD::getVIN(char* buffer, byte bufsize)
 {
-	if (sendCommand("0902\r", buffer, bufsize)) {
-        char *p = strstr(buffer, "0: 49 02");
-        if (p) {
-            char *q = buffer;
-            p += 10;
-            do {
-                for (++p; *p == ' '; p += 3) {
-                    if (*q = hex2uint8(p + 1)) q++;
-                }
-                p = strchr(p, ':');
-            } while(p);
-            *q = 0;
-            return true;
-        }
+	for (byte n = 0; n < 5; n++) {
+		if (sendCommand("0902\r", buffer, bufsize)) {
+			int len = hex2uint16(buffer);
+			char *p = strstr_P(buffer + 4, PSTR("0: 49 02 01"));
+			if (p) {
+				char *q = buffer;
+				p += 11; // skip the header
+				do {
+					while (*(++p) == ' ');
+					for (;;) {
+						*(q++) = hex2uint8(p);
+						while (*p && *p != ' ') p++;
+						while (*p == ' ') p++;
+						if (!*p || *p == '\r') break;
+					}
+					p = strchr(p, ':');
+				} while(p);
+				*q = 0;
+				if (q - buffer == len - 3) {
+					return true;
+				}
+			}
+		}
+		delay(100);
     }
     return false;
 }
@@ -362,7 +365,7 @@ byte COBD::getVersion()
 	return version;
 }
 
-byte COBD::receive(char* buffer, byte bufsize, int timeout)
+int COBD::receive(char* buffer, int bufsize, unsigned int timeout)
 {
 	unsigned char n = 0;
 	unsigned long startTime = millis();
@@ -393,7 +396,7 @@ byte COBD::receive(char* buffer, byte bufsize, int timeout)
 			    // timeout
 			    break;
 			}
-			dataIdleLoop();
+			idleTasks();
 		}
 	}
 	if (buffer) {
@@ -415,48 +418,77 @@ bool COBD::init(OBD_PROTOCOLS protocol)
 {
 	const char *initcmd[] = {"ATZ\r", "ATE0\r", "ATH0\r"};
 	char buffer[64];
+	byte stage;
 
 	m_state = OBD_DISCONNECTED;
-	for (unsigned char i = 0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
-		write(initcmd[i]);
-		if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) == 0) {
-			return false;
+
+	for (byte n = 0; n < 2; n++) {
+		stage = 0;
+		if (n != 0) reset();
+		for (byte i = 0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
+			delay(10);
+			if (!sendCommand(initcmd[i], buffer, sizeof(buffer), OBD_TIMEOUT_SHORT)) {
+				continue;
+			}
 		}
-	}
-	if (protocol != PROTO_AUTO) {
-		sprintf_P(buffer, PSTR("ATSP %u\r"), protocol);
-		write(buffer);
-		if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) == 0 && !strstr(buffer, "OK")) {
-			return false;
+		stage = 1;
+		if (protocol != PROTO_AUTO) {
+			sprintf(buffer, "ATSP%u\r", protocol);
+			delay(10);
+			if (!sendCommand(buffer, buffer, sizeof(buffer), OBD_TIMEOUT_SHORT) || !strstr(buffer, "OK")) {
+				continue;
+			}
 		}
-	}
-
-	// load pid map
-	memset(pidmap, 0, sizeof(pidmap));
-	bool success = false;
-	for (byte i = 0; i < 4; i++) {
-		byte pid = i * 0x20;
-		sendQuery(pid);
-		if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) > 0) {
-			char *p = buffer;
-			while ((p = strstr(p, "41 "))) {
-				p += 3;
-				if (hex2uint8(p) == pid) {
-					p += 2;
-					for (byte n = 0; n < 4 && *(p + n * 3) == ' '; n++) {
-						pidmap[i * 4 + n] = hex2uint8(p + n * 3 + 1);
+		stage = 2;
+		delay(10);
+		if (!sendCommand("010D\r", buffer, sizeof(buffer), OBD_TIMEOUT_LONG) || checkErrorMessage(buffer)) {
+			continue;
+		}
+		stage = 3;
+		// load pid map
+		memset(pidmap, 0, sizeof(pidmap));
+		bool success = false;
+		for (byte i = 0; i < 4; i++) {
+			byte pid = i * 0x20;
+			sprintf(buffer, "%02X%02X\r", dataMode, pid);
+			delay(10);
+			write(buffer);
+			if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) > 0) {
+				if (checkErrorMessage(buffer)) {
+					break;
+				}
+				char *p = buffer;
+				while ((p = strstr(p, "41 "))) {
+					p += 3;
+					if (hex2uint8(p) == pid) {
+						p += 2;
+						for (byte n = 0; n < 4 && *(p + n * 3) == ' '; n++) {
+							pidmap[i * 4 + n] = hex2uint8(p + n * 3 + 1);
+						}
+						success = true;
 					}
-					success = true;
 				}
+			} else {
+				break;
 			}
 		}
+		if (success) {
+			stage = 0xff;
+			break;
+		}
 	}
-
-	if (success) {
+	if (stage == 0xff) {
 		m_state = OBD_CONNECTED;
 		errors = 0;
+		return true;
+	} else {
+#ifdef DEBUG
+		Serial.print("Stage:");
+		Serial.println(stage);
+#endif
+		reset();
+		return false;
 	}
-	return success;
 }
 
 void COBD::end()
@@ -477,10 +509,64 @@ bool COBD::setBaudRate(unsigned long baudrate)
     return true;
 }
 
-bool COBD::memsInit()
+void COBD::reset()
+{
+	char buf[32];
+	sendCommand("ATR\r", buf, sizeof(buf));
+	delay(3000);
+	sendCommand("ATZ\r", buf, sizeof(buf));
+}
+
+void COBD::uninit()
+{
+	char buf[32];
+	sendCommand("ATPC\r", buf, sizeof(buf));
+}
+
+byte COBD::checkErrorMessage(const char* buffer)
+{
+	const char *errmsg[] = {"UNABLE", "ERROR", "TIMEOUT", "NO DATA"};
+	for (byte i = 0; i < sizeof(errmsg) / sizeof(errmsg[0]); i++) {
+		if (strstr(buffer, errmsg[i])) return i + 1;
+	}
+	return 0;
+}
+
+uint8_t COBD::getPercentageValue(char* data)
+{
+  return (uint16_t)hex2uint8(data) * 100 / 255;
+}
+
+uint16_t COBD::getLargeValue(char* data)
+{
+  return hex2uint16(data);
+}
+
+uint8_t COBD::getSmallValue(char* data)
+{
+  return hex2uint8(data);
+}
+
+int16_t COBD::getTemperatureValue(char* data)
+{
+  return (int)hex2uint8(data) - 40;
+}
+
+bool COBD::memsInit(bool fusion)
 {
 	char buf[16];
-	return sendCommand("ATTEMP\r", buf, sizeof(buf)) > 0 && !strchr(buf, '?');
+	if (!sendCommand("ATTEMP\r", buf, sizeof(buf)) > 0 || strchr(buf, '?'))
+		return false;
+	if (fusion) {
+		m_fusion = true;
+		return sendCommand("ATQU1\r", buf, sizeof(buf));
+	} else {
+		if (m_fusion) {
+			m_fusion = false;
+			sendCommand("ATQU0\r", buf, sizeof(buf));
+		}
+		return true;
+	}
 }
 
 bool COBD::memsRead(int16_t* acc, int16_t* gyr, int16_t* mag, int16_t* temp)
@@ -515,6 +601,20 @@ bool COBD::memsRead(int16_t* acc, int16_t* gyr, int16_t* mag, int16_t* temp)
 		} while (0);
 		if (!success) return false;
 	}
+	if (mag) {
+		success = false;
+		if (sendCommand("ATMAG\r", buf, sizeof(buf)) > 0) do {
+			char* p = getResultValue(buf);
+			if (!p) break;
+			mag[0] = atoi(p++);
+			if (!(p = strchr(p, ','))) break;
+			mag[1] = atoi(++p);
+			if (!(p = strchr(p, ','))) break;
+			mag[2] = atoi(++p);
+			success = true;
+		} while (0);
+		if (!success) return false;
+	}
 	if (temp) {
 		success = false;
 		if (sendCommand("ATTEMP\r", buf, sizeof(buf)) > 0) {
@@ -529,6 +629,24 @@ bool COBD::memsRead(int16_t* acc, int16_t* gyr, int16_t* mag, int16_t* temp)
 	return true;	
 }
 
+bool COBD::memsOrientation(float& yaw, float& pitch, float& roll)
+{
+	char buf[64];
+	bool success = false;
+	if (sendCommand("ATORI\r", buf, sizeof(buf)) > 0) do {
+		Serial.println(buf);
+		char* p = getResultValue(buf);
+		if (!p) break;
+		yaw = (float)atof(p++);
+		if (!(p = strchr(p, ','))) break;
+		pitch = (float)atoi(++p);
+		if (!(p = strchr(p, ','))) break;
+		roll = (float) atof(++p);
+		success = true;
+	} while (0);
+	return success;
+}
+
 #ifdef DEBUG
 void COBD::debugOutput(const char *s)
 {
diff --git a/libraries/OBD2UART/OBD2UART.h b/libraries/OBD2UART/OBD2UART.h
index 62ac18b..2674274 100644
--- a/libraries/OBD2UART/OBD2UART.h
+++ b/libraries/OBD2UART/OBD2UART.h
@@ -8,8 +8,7 @@
 #include <Arduino.h>
 
 #define OBD_TIMEOUT_SHORT 1000 /* ms */
-#define OBD_TIMEOUT_LONG 5000 /* ms */
-#define OBD_TIMEOUT_GPS 200 /* ms */
+#define OBD_TIMEOUT_LONG 10000 /* ms */
 
 #ifndef OBDUART
 #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168P__)
@@ -19,6 +18,10 @@
 #endif
 #endif
 
+#ifdef ESP32
+extern HardwareSerial Serial1;
+#endif
+
 // Mode 1 PIDs
 #define PID_ENGINE_LOAD 0x04
 #define PID_COOLANT_TEMP 0x05
@@ -73,23 +76,12 @@
 #define PID_ENGINE_REF_TORQUE 0x63
 
 // non-OBD/custom PIDs (no mode number)
-#define PID_GPS_LATITUDE 0xA
-#define PID_GPS_LONGITUDE 0xB
-#define PID_GPS_ALTITUDE 0xC
-#define PID_GPS_SPEED 0xD
-#define PID_GPS_HEADING 0xE
-#define PID_GPS_SAT_COUNT 0xF
-#define PID_GPS_TIME 0x10
-#define PID_GPS_DATE 0x11
 #define PID_ACC 0x20
 #define PID_GYRO 0x21
 #define PID_COMPASS 0x22
 #define PID_MEMS_TEMP 0x23
 #define PID_BATTERY_VOLTAGE 0x24
 
-// custom PIDs for calculated data
-#define PID_TRIP_DISTANCE 0x30
-
 typedef enum {
     PROTO_AUTO = 0,
     PROTO_ISO_9141_2 = 3,
@@ -115,13 +107,16 @@ uint8_t hex2uint8(const char *p);
 class COBD
 {
 public:
-	COBD():dataMode(1),errors(0),m_state(OBD_DISCONNECTED) {}
 	// begin serial UART
 	virtual byte begin();
+	// terminate communication channel
+	virtual void end();
 	// initialize OBD-II connection
 	virtual bool init(OBD_PROTOCOLS protocol = PROTO_AUTO);
+	// reset OBD-II connection
+	virtual void reset();
 	// un-initialize OBD-II connection
-	virtual void end();
+	virtual void uninit();
 	// set serial baud rate
 	virtual bool setBaudRate(unsigned long baudrate);
 	// get connection state
@@ -144,12 +139,12 @@ public:
 	virtual float getVoltage();
 	// get VIN as a string, buffer length should be >= OBD_RECV_BUF_SIZE
 	virtual bool getVIN(char* buffer, byte bufsize);
-	// initialize MEMS sensor
-	virtual bool memsInit();
+	// initialize MEMS sensor (enable or disable sensor fusion by quanterion algorithm)
+	virtual bool memsInit(bool fusion = false);
 	// read out MEMS data (acc for accelerometer, gyr for gyroscope, temp in 0.1 celcius degree)
 	virtual bool memsRead(int16_t* acc, int16_t* gyr = 0, int16_t* mag = 0, int16_t* temp = 0);
-	// send query for specified PID
-	virtual void sendQuery(byte pid);
+	// get computed orientation values
+	virtual bool memsOrientation(float& yaw, float& pitch, float& roll);
 	// retrive and parse the response of specifie PID
 	virtual bool getResult(byte& pid, int& result);
 	// determine if the PID is supported
@@ -157,37 +152,26 @@ public:
 	// get adapter firmware version
 	virtual byte getVersion();
 	// set current PID mode
-	byte dataMode;
+	byte dataMode = 1;
 	// occurrence of errors
-	byte errors;
+	byte errors = 0;
 	// bit map of supported PIDs
-	byte pidmap[4 * 4];
+	byte pidmap[4 * 4] = {0};
 protected:
 	virtual char* getResponse(byte& pid, char* buffer, byte bufsize);
-	virtual byte receive(char* buffer, byte bufsize, int timeout = OBD_TIMEOUT_SHORT);
+	virtual int receive(char* buffer, int bufsize, unsigned int timeout = OBD_TIMEOUT_SHORT);
 	virtual void write(const char* s);
-	virtual void dataIdleLoop() {}
-	void recover();
-	void debugOutput(const char* s);
-	int normalizeData(byte pid, char* data);
-	OBD_STATES m_state;
+	virtual uint8_t getPercentageValue(char* data);
+	virtual uint16_t getLargeValue(char* data);
+	virtual uint8_t getSmallValue(char* data);
+	virtual int16_t getTemperatureValue(char* data);
+	virtual int normalizeData(byte pid, char* data);
+	virtual byte checkErrorMessage(const char* buffer);
+	virtual char* getResultValue(char* buf);
+	OBD_STATES m_state = OBD_DISCONNECTED;
 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;
-	}
-	char* getResultValue(char* buf);
+	void recover();
+	virtual void idleTasks() {}
+	bool m_fusion = false;
 };
 
diff --git a/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino b/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino
index 9b11eab..4d30b0e 100644
--- a/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino
+++ b/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino
@@ -1,25 +1,32 @@
 /*************************************************************************
-* Testing sketch for Freematics OBD-II UART Adapter
+* Testing sketch for Freematics OBD-II UART Adapter V1/V2/V2.1
+* Performs AT command-set test
 * Reads and prints several OBD-II PIDs value
-* Distributed under GPL v2.0
-* Visit http://freematics.com for more information
-* Written by Stanley Huang <support@freematics.com.au>
+* Reads and prints motion sensor data if available
+* Distributed under BSD
+* Visit https://freematics.com/products for more product information
+* Written by Stanley Huang <stanley@freematics.com.au>
 *************************************************************************/
 
-#include <SoftwareSerial.h>
 #include <OBD2UART.h>
 
-// On Arduino Leonardo, Micro, MEGA or DUE, hardware serial can be used for output
-// as OBD-II UART adapter uses to Serial1
-// On Arduino UNO and those have no Serial1, we use software serial for output
-// as OBD-II UART adapter uses to Serial
+// On Arduino Leonardo, Micro, MEGA or DUE, hardware serial can be used for output as the adapter occupies Serial1
+// On Arduino UNO and those have no Serial1, we use software serial for output as the adapter uses Serial
+#ifdef ARDUINO_AVR_UNO
+#include <SoftwareSerial.h>
 SoftwareSerial mySerial(A2, A3);
-//#define mySerial Serial
+#else
+#define mySerial Serial
+#endif
+
+#if defined(ESP32) && !defined(Serial1)
+HardwareSerial Serial1(1);
+#endif
 
 COBD obd;
 bool hasMEMS;
 
-void testOut()
+void testATcommands()
 {
     static const char cmds[][6] = {"ATZ\r", "ATI\r", "ATH0\r", "ATRV\r", "0100\r", "010C\r", "0902\r"};
     char buf[128];
@@ -93,11 +100,12 @@ void readBatteryVoltage()
 
 void readMEMS()
 {
-  int acc[3];
-  int gyro[3];
-  int temp;
+  int16_t acc[3] = {0};
+  int16_t gyro[3] = {0};
+  int16_t mag[3] = {0};
+  int16_t temp = 0;
 
-  if (!obd.memsRead(acc, gyro, 0, &temp)) return;
+  if (!obd.memsRead(acc, gyro, mag, &temp)) return;
 
   mySerial.print('[');
   mySerial.print(millis());
@@ -117,6 +125,13 @@ void readMEMS()
   mySerial.print('/');
   mySerial.print(gyro[2]);
 
+  mySerial.print(" MAG:");
+  mySerial.print(mag[0]);
+  mySerial.print('/');
+  mySerial.print(mag[1]);
+  mySerial.print('/');
+  mySerial.print(mag[2]);
+
   mySerial.print(" TEMP:");
   mySerial.print((float)temp / 10, 1);
   mySerial.println("C");
@@ -127,23 +142,24 @@ void setup()
   mySerial.begin(115200);
   while (!mySerial);
   
-  // this will begin serial
-  byte version = obd.begin();
-
-  mySerial.print("Freematics OBD-II Adapter ");
-  if (version > 0) {
-    mySerial.print("Ver. ");
-    mySerial.print(version / 10);
-    mySerial.print('.');
-    mySerial.println(version % 10);
-  } else {
-    mySerial.println("not detected");
-    for (;;);
+  for (;;) {
+    delay(1000);
+    byte version = obd.begin();
+    mySerial.print("Freematics OBD-II Adapter ");
+    if (version > 0) {
+      mySerial.println("detected");
+      mySerial.print("OBD firmware version ");
+      mySerial.print(version / 10);
+      mySerial.print('.');
+      mySerial.println(version % 10);
+      break;
+    } else {
+      mySerial.println("not detected");
+    }
   }
-  delay(1000);
 
   // send some commands for testing and show response for debugging purpose
-  testOut();
+  testATcommands();
 
   hasMEMS = obd.memsInit();
   mySerial.print("MEMS:");
@@ -151,8 +167,9 @@ void setup()
   
   // initialize OBD-II adapter
   do {
-    mySerial.println("Init...");
+    mySerial.println("Connecting...");
   } while (!obd.init());
+  mySerial.println("OBD connected!");
 
   char buf[64];
   if (obd.getVIN(buf, sizeof(buf))) {
@@ -160,7 +177,7 @@ void setup()
       mySerial.println(buf);
   }
   
-  unsigned int codes[6];
+  uint16_t codes[6];
   byte dtcCount = obd.readDTC(codes, 6);
   if (dtcCount == 0) {
     mySerial.println("No DTC"); 
@@ -176,7 +193,6 @@ void setup()
   delay(5000);
 }
 
-
 void loop()
 {
   readPIDSingle();
@@ -186,3 +202,4 @@ void loop()
     readMEMS();
   }
 }
+
diff --git a/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino b/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino
new file mode 100644
index 0000000..923c6ac
--- /dev/null
+++ b/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino
@@ -0,0 +1,98 @@
+/*************************************************************************
+* Testing sketch for Freematics OBD-II UART Adapter V2.1
+* Reads and prints motion sensor data and computed orientation data
+* Distributed under BSD
+* Visit https://freematics.com/products for more product information
+* Written by Stanley Huang <stanley@freematics.com.au>
+*************************************************************************/
+
+#include <OBD2UART.h>
+
+// On Arduino Leonardo, Micro, MEGA or DUE, hardware serial can be used for output as the adapter occupies Serial1
+// On Arduino UNO and those have no Serial1, we use software serial for output as the adapter uses Serial
+#ifdef ARDUINO_AVR_UNO
+#include <SoftwareSerial.h>
+SoftwareSerial mySerial(A2, A3);
+#else
+#define mySerial Serial
+#endif
+
+#if defined(ESP32) && !defined(Serial1)
+HardwareSerial Serial1(1);
+#endif
+
+COBD obd;
+bool hasMEMS;
+
+void setup()
+{
+  mySerial.begin(115200);
+  while (!mySerial);
+  
+  // this will begin serial
+
+  for (;;) {
+    delay(1000);
+    byte version = obd.begin();
+    mySerial.print("Freematics OBD-II Adapter ");
+    if (version > 0) {
+      mySerial.println("detected");
+      break;
+    } else {
+      mySerial.println("not detected");
+    }
+  }
+  
+  // initialize MEMS with sensor fusion enabled
+  hasMEMS = obd.memsInit(true);
+  mySerial.print("MEMS:");
+  mySerial.println(hasMEMS ? "OK" : "NO");
+  if (!hasMEMS) {
+    for (;;);
+  }
+}
+
+
+void loop()
+{
+  int16_t acc[3] = {0};
+  int16_t gyro[3] = {0};
+  int16_t mag[3] = {0};
+
+  if (!obd.memsRead(acc, gyro, mag)) return;
+  
+  mySerial.print("ACC:");
+  mySerial.print(acc[0]);
+  mySerial.print('/');
+  mySerial.print(acc[1]);
+  mySerial.print('/');
+  mySerial.print(acc[2]);
+
+  mySerial.print(" GYRO:");
+  mySerial.print(gyro[0]);
+  mySerial.print('/');
+  mySerial.print(gyro[1]);
+  mySerial.print('/');
+  mySerial.print(gyro[2]);
+
+  mySerial.print(" MAG:");
+  mySerial.print(mag[0]);
+  mySerial.print('/');
+  mySerial.print(mag[1]);
+  mySerial.print('/');
+  mySerial.print(mag[2]);
+
+  mySerial.println();
+
+  float yaw, pitch, roll;
+  if (obd.memsOrientation(yaw, pitch, roll)) {
+    mySerial.print("Orientation: ");
+    mySerial.print(yaw, 2);
+    mySerial.print(' ');
+    mySerial.print(pitch, 2);
+    mySerial.print(' ');
+    mySerial.println(roll, 2);
+  }
+
+  delay(100);
+}
diff --git a/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino b/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino
index 3e80ae3..5b7a13e 100644
--- a/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino
+++ b/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino
@@ -1,8 +1,9 @@
 /*************************************************************************
-* Sample sketch based on OBD-II library for Arduino
-* Distributed under GPL v2.0
-* Visit http://freematics.com for more information
-* (C)2012-2014 Stanley Huang <stanleyhuangyc@gmail.com>
+* Testing sketch for Freematics OBD-II UART Adapter
+* Reads engine RPM data from OBD and triggers Arduino onboard LED
+* Distributed under BSD
+* Visit https://freematics.com/products for more product information
+* Written by Stanley Huang <stanley@freematics.com.au>
 *************************************************************************/
 
 #include <OBD2UART.h>
diff --git a/libraries/OBD2UART/keywords.txt b/libraries/OBD2UART/keywords.txt
new file mode 100644
index 0000000..316a4fb
--- /dev/null
+++ b/libraries/OBD2UART/keywords.txt
@@ -0,0 +1,29 @@
+################################################################################
+# Datatypes (KEYWORD1)
+################################################################################
+COBD	KEYWORD1
+
+################################################################################
+# Methods and Functions (KEYWORD2)
+################################################################################
+begin	KEYWORD2
+end	KEYWORD2
+init	KEYWORD2
+uninit	KEYWORD2
+reset	KEYWORD2
+
+readPID	KEYWORD2
+readDTC	KEYWORD2
+clearDTC	KEYWORD2
+getVoltage	KEYWORD2
+getVIN	KEYWORD2
+
+memsInit KEYWORD2
+memsRead KEYWORD2
+memsOrientation KEYWORD2
+
+################################################################################
+# Constants (LITERAL1)
+################################################################################
+OBD_PROTOCOLS	LITERAL1
+OBD_STATES	LITERAL1
\ No newline at end of file
diff --git a/libraries/OBD2UART/library.properties b/libraries/OBD2UART/library.properties
new file mode 100644
index 0000000..cbb921d
--- /dev/null
+++ b/libraries/OBD2UART/library.properties
@@ -0,0 +1,9 @@
+name=OBD2UART
+version=1.2
+author=Stanley Huang <stanley@freematics.com.au>
+maintainer=Stanley Huang <stanley@freematics.com.au>
+sentence=Arduino library for Freematics OBD-II UART Adapter
+paragraph=Arduino library for Freematics OBD-II UART Adapter
+category=Communication
+url=https://freematics.com
+includes=OBD2UART.h
\ No newline at end of file
-- 
cgit v1.2.3


From ec35ee0fab747dd7a7ef9f0996970b094a00d4f3 Mon Sep 17 00:00:00 2001
From: Stanley Huang <stanleyhuangyc@gmail.com>
Date: Tue, 30 Jan 2018 22:51:39 +1100
Subject: Add support for Freematics OBD-II UART Adapter V2.1

---
 libraries/OBD2UART/OBD2UART.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'libraries')

diff --git a/libraries/OBD2UART/OBD2UART.cpp b/libraries/OBD2UART/OBD2UART.cpp
index 8406251..826b3d2 100644
--- a/libraries/OBD2UART/OBD2UART.cpp
+++ b/libraries/OBD2UART/OBD2UART.cpp
@@ -634,7 +634,6 @@ bool COBD::memsOrientation(float& yaw, float& pitch, float& roll)
 	char buf[64];
 	bool success = false;
 	if (sendCommand("ATORI\r", buf, sizeof(buf)) > 0) do {
-		Serial.println(buf);
 		char* p = getResultValue(buf);
 		if (!p) break;
 		yaw = (float)atof(p++);
-- 
cgit v1.2.3


From 25d95246ea97492ac0979d27e807ff3e8e3a9775 Mon Sep 17 00:00:00 2001
From: Stanley Huang <stanleyhuangyc@gmail.com>
Date: Wed, 31 Jan 2018 11:52:45 +1100
Subject: Update

---
 .../OBD2UART/examples/orientation_demo/orientation_demo.ino      | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

(limited to 'libraries')

diff --git a/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino b/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino
index 923c6ac..e04949c 100644
--- a/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino
+++ b/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino
@@ -22,7 +22,6 @@ HardwareSerial Serial1(1);
 #endif
 
 COBD obd;
-bool hasMEMS;
 
 void setup()
 {
@@ -44,11 +43,11 @@ void setup()
   }
   
   // initialize MEMS with sensor fusion enabled
-  hasMEMS = obd.memsInit(true);
-  mySerial.print("MEMS:");
-  mySerial.println(hasMEMS ? "OK" : "NO");
+  bool hasMEMS = obd.memsInit(true);
+  mySerial.print("Motion sensor is ");
+  mySerial.println(hasMEMS ? "present" : "not present");
   if (!hasMEMS) {
-    for (;;);
+    for (;;) delay(1000);
   }
 }
 
-- 
cgit v1.2.3


From 33999a3101275925071ad9f5b2b31d914e2c6b94 Mon Sep 17 00:00:00 2001
From: Stanley Huang <stanleyhuangyc@gmail.com>
Date: Wed, 31 Jan 2018 22:32:00 +1100
Subject: Fix typo

---
 libraries/OBD2UART/OBD2UART.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

(limited to 'libraries')

diff --git a/libraries/OBD2UART/OBD2UART.cpp b/libraries/OBD2UART/OBD2UART.cpp
index 826b3d2..76968b9 100644
--- a/libraries/OBD2UART/OBD2UART.cpp
+++ b/libraries/OBD2UART/OBD2UART.cpp
@@ -9,10 +9,6 @@
 
 //#define DEBUG Serial
 
-#ifdef ESP32
-extern HardwareSerial Serial1;
-#endif
-
 uint16_t hex2uint16(const char *p)
 {
 	char c = *p;
@@ -555,7 +551,7 @@ int16_t COBD::getTemperatureValue(char* data)
 bool COBD::memsInit(bool fusion)
 {
 	char buf[16];
-	if (!sendCommand("ATTEMP\r", buf, sizeof(buf)) > 0 || strchr(buf, '?'))
+	if (sendCommand("ATTEMP\r", buf, sizeof(buf)) <= 0 || strchr(buf, '?'))
 		return false;
 	if (fusion) {
 		m_fusion = true;
-- 
cgit v1.2.3