summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanley Huang <stanleyhuangyc@gmail.com>2017-04-09 10:22:56 +1000
committerStanley Huang <stanleyhuangyc@gmail.com>2017-04-09 10:22:56 +1000
commit7562899738e6d06d13f5c76a9b83574468fc396c (patch)
treee12b24be5f181be994539cfd6680729dc8e90fa4
parent63dd1468f6684e6621d48d4f7bdf726e29efb975 (diff)
download2021-arduino-obd-7562899738e6d06d13f5c76a9b83574468fc396c.tar.gz
2021-arduino-obd-7562899738e6d06d13f5c76a9b83574468fc396c.tar.bz2
2021-arduino-obd-7562899738e6d06d13f5c76a9b83574468fc396c.zip
OBD-II data logger on ESP32 or ESP8266
-rw-r--r--esplogger/datalogger.h456
-rw-r--r--esplogger/esplogger.ino14
2 files changed, 175 insertions, 295 deletions
diff --git a/esplogger/datalogger.h b/esplogger/datalogger.h
index 8009a80..6c4b60a 100644
--- a/esplogger/datalogger.h
+++ b/esplogger/datalogger.h
@@ -1,13 +1,12 @@
-#define FORMAT_BIN 0
-#define FORMAT_CSV 1
+/*************************************************************************
+* Freematics Data Logger Class
+* Distributed under GPL v2.0
+* Written by Stanley Huang <stanleyhuangyc@gmail.com>
+* Visit http://freematics.com for more information
+*************************************************************************/
-typedef struct {
- uint32_t time;
- uint16_t pid;
- uint8_t flags;
- uint8_t checksum;
- float value;
-} LOG_DATA;
+#define FORMAT_BIN 0
+#define FORMAT_TEXT 1
typedef struct {
uint32_t time;
@@ -17,337 +16,210 @@ typedef struct {
float value[3];
} LOG_DATA_COMM;
-typedef struct {
- uint32_t time; /* e.g. 1307281259 */
- uint16_t pid;
- uint8_t message;
- uint8_t checksum;
- uint16_t fileIndex;
- uint16_t fileSize; /* KB */
- uint16_t logFlags;
- uint8_t logType;
- uint8_t data[5];
-} LOG_DATA_FILE_INFO;
+#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
-typedef struct {
- uint32_t time;
- uint16_t pid;
- uint8_t message;
- uint8_t checksum;
- uint8_t data[12];
-} LOG_DATA_COMMAND;
+#define PID_ACC 0x20
+#define PID_GYRO 0x21
+#define PID_COMPASS 0x22
+#define PID_MEMS_TEMP 0x23
+#define PID_BATTERY_VOLTAGE 0x24
-typedef struct {
- uint32_t id;
- uint32_t dataOffset;
- uint8_t ver;
- uint8_t logType;
- uint16_t flags;
- uint32_t dateTime; //4, YYMMDDHHMM, e.g. 1305291359
- /*
- uint8_t devid[8];
- uint8_t vin[24];
- uint8_t unused[84];
- */
-} HEADER;
+#define PID_DATA_SIZE 0x80
-#define HEADER_LEN 128 /* bytes */
-
-#define PID_GPS_COORDINATES 0xF00A
-#define PID_GPS_ALTITUDE 0xF00C
-#define PID_GPS_SPEED 0xF00D
-#define PID_GPS_HEADING 0xF00E
-#define PID_GPS_SAT_COUNT 0xF00F
-#define PID_GPS_TIME 0xF010
-
-#define PID_ACC 0xF020
-#define PID_GYRO 0xF021
-
-#define PID_MESSAGE 0xFE00
-#define PID_HEART_BEAT 0xFFEE
-
-#define MSG_FILE_LIST_BEGIN 0x1
-#define MSG_FILE_LIST_END 0x2
-#define MSG_FILE_INFO 0x3
-#define MSG_FILE_REQUEST 0x4
-
-#if LOG_FORMAT == FORMAT_BIN
-#define FILE_NAME_FORMAT "/DAT%05d.LOG"
-#else
-#define FILE_NAME_FORMAT "/DAT%05d.CSV"
-#endif
+#define FILE_NAME_FORMAT "DAT%05d.CSV"
+#define FILE_PATH "/DATA/"
#if ENABLE_DATA_OUT
#if USE_SOFTSERIAL
-
-#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
- SoftwareSerial SerialBLE(A8, A9); /* for BLE Shield on MEGA*/
-#elif defined(__AVR_ATmega644P__)
- SoftwareSerial SerialBLE(9, 10); /* for Microduino */
+SoftwareSerial SerialRF(A2, A3);
+#elif defined(RF_SERIAL)
+#define SerialRF RF_SERIAL
#else
- SoftwareSerial SerialBLE(A2, A3); /* for BLE Shield on UNO/leonardo*/
+#define SerialRF Serial
#endif
-#define OUTPUT_BAUDRATE 9600
-
-#else
-
-#define SerialBLE Serial
-#define OUTPUT_BAUDRATE 115200
-
#endif
+#if ENABLE_DATA_LOG
+static File sdfile;
#endif
-void btInit(int baudrate);
-void btSend(byte* data, byte length);
+typedef struct {
+ uint8_t pid;
+ char name[3];
+} PID_NAME;
+
+const PID_NAME pidNames[] PROGMEM = {
+{PID_ACC, {'A','C','C'}},
+{PID_GYRO, {'G','Y','R'}},
+{PID_COMPASS, {'M','A','G'}},
+{PID_GPS_LATITUDE, {'L','A','T'}},
+{PID_GPS_LONGITUDE, {'L','N','G'}},
+{PID_GPS_ALTITUDE, {'A','L','T'}},
+{PID_GPS_SPEED, {'S','P','D'}},
+{PID_GPS_HEADING, {'C','R','S'}},
+{PID_GPS_SAT_COUNT, {'S','A','T'}},
+{PID_GPS_TIME, {'U','T','C'}},
+{PID_GPS_DATE, {'D','T','E'}},
+{PID_BATTERY_VOLTAGE, {'B','A','T'}},
+{PID_DATA_SIZE, {'D','A','T'}},
+};
class CDataLogger {
public:
- void initSender()
+ CDataLogger()
{
-#if ENABLE_DATA_OUT
- SerialBLE.begin(OUTPUT_BAUDRATE);
-#endif
-#if ENABLE_DATA_LOG && LOG_FORMAT == FORMAT_CSV
m_lastDataTime = 0;
+#if ENABLE_DATA_CACHE
+ cacheBytes = 0;
#endif
}
-#if ENABLE_DATA_OUT
- void sendFileInfo(File& file)
- {
- if (file.size() < HEADER_LEN) return;
-
- LOG_DATA_FILE_INFO info = {0};
- info.fileIndex = atol(file.name() + 3);
- if (info.fileIndex == 0) return;
-
- HEADER hdr;
- if (file.readBytes((char*)&hdr, sizeof(hdr)) != sizeof(hdr)) return;
-
- info.pid = PID_MESSAGE;
- info.message = MSG_FILE_INFO;
- info.fileSize = file.size();
- info.time = hdr.dateTime;
- info.logType = hdr.logType;
- info.logFlags = hdr.flags;
- info.checksum = getChecksum((char*)&info, sizeof(info));
- SerialBLE.write((uint8_t*)&info, sizeof(info));
- }
- void sendCommand(byte message, void* data = 0, byte bytes = 0)
+ void initSender()
{
- LOG_DATA_COMMAND msg = {0, PID_MESSAGE, message};
- if (data) memcpy(msg.data, data, bytes);
- msg.checksum = getChecksum((char*)&msg, sizeof(msg));
- SerialBLE.write((uint8_t*)&msg, sizeof(msg));
+#if ENABLE_DATA_OUT
+ SerialRF.begin(STREAM_BAUDRATE);
+#endif
}
- bool receiveCommand(LOG_DATA_COMMAND& msg)
+ byte genTimestamp(char* buf, bool absolute)
{
- if (!SerialBLE.available())
- return false;
-
- if (SerialBLE.readBytes((char*)&msg, sizeof(msg)) != sizeof(msg))
- return false;
-
- uint8_t checksum = msg.checksum;
- msg.checksum = 0;
- if (getChecksum((char*)&msg, sizeof(msg)) != msg.checksum) {
- return false;
- }
- return true;
+ byte n;
+ if (absolute || dataTime >= m_lastDataTime + 60000) {
+ // absolute timestamp
+ n = sprintf(buf, "#%lu,", dataTime);
+ } else {
+ // incremental timestamp
+ n = sprintf(buf, "%u,", (unsigned int)(dataTime - m_lastDataTime));
+ }
+ return n;
}
-#endif
- void logData(uint16_t pid, int value)
+ void record(const char* buf, byte len)
{
-#if LOG_FORMAT == FORMAT_BIN || STREAM_FORMAT == FORMAT_BIN
- LOG_DATA_COMM ld = {dataTime, pid, 1, 0, value};
- ld.checksum = getChecksum((char*)&ld, 12);
-#endif
-#if ENABLE_DATA_OUT
-#if STREAM_FORMAT == FORMAT_BIN
- SerialBLE.write((uint8_t*)&ld, 12);
-#else
- SerialBLE.print(pid, HEX);
- SerialBLE.write(',');
- SerialBLE.print(value);
- SerialBLE.write('\n');
-#endif
-#endif
#if ENABLE_DATA_LOG
- if (!sdfile) return;
-#if LOG_FORMAT == FORMAT_BIN
- sdfile.write((uint8_t*)&ld, 12);
- dataSize += 12;
+#if STREAM_FORMAT == FORMAT_BIN
+ dataSize += sdfile.write(buf, len);
#else
- dataSize += sdfile.print(dataTime - m_lastDataTime);
- sdfile.write(',');
- dataSize += sdfile.print(pid, HEX);
- sdfile.write(',');
- dataSize += sdfile.print(value);
- sdfile.write('\n');
+ char tmp[12];
+ byte n = genTimestamp(tmp, dataSize == 0);
+ dataSize += sdfile.write(tmp, n);
+ dataSize += sdfile.write(buf, len);
+ sdfile.println();
dataSize += 3;
- m_lastDataTime = dataTime;
#endif
#endif
+ m_lastDataTime = dataTime;
}
- void logData(uint16_t pid, float value)
+ void dispatch(const char* buf, byte len)
{
-#if LOG_FORMAT == FORMAT_BIN || STREAM_FORMAT == FORMAT_BIN
- LOG_DATA_COMM ld = {dataTime, pid, 1, 0, value};
- ld.checksum = getChecksum((char*)&ld, 12);
+#if ENABLE_DATA_CACHE
+ if (cacheBytes + len < MAX_CACHE_SIZE - 10) {
+ cacheBytes += genTimestamp(cache + cacheBytes, cacheBytes == 0);
+ memcpy(cache + cacheBytes, buf, len);
+ cacheBytes += len;
+ cache[cacheBytes++] = '\n';
+ cache[cacheBytes] = 0;
+ }
#endif
#if ENABLE_DATA_OUT
-#if STREAM_FORMAT == FORMAT_BIN
- SerialBLE.write((uint8_t*)&ld, 12);
-#else
- SerialBLE.print(pid, HEX);
- SerialBLE.write(',');
- SerialBLE.print(value);
- SerialBLE.write('\n');
+ SerialRF.write(buf, len);
+ SerialRF.println();
#endif
-#endif
-#if ENABLE_DATA_LOG
- if (!sdfile) return;
-#if LOG_FORMAT == FORMAT_BIN
- sdfile.write((uint8_t*)&ld, 12);
- dataSize += 12;
-#else
- dataSize += sdfile.print(dataTime - m_lastDataTime);
- sdfile.write(',');
- dataSize += sdfile.print(pid, HEX);
- sdfile.write(',');
- dataSize += sdfile.print(value);
- sdfile.write('\n');
- dataSize += 3;
- m_lastDataTime = dataTime;
+ }
+ void logData(const char* buf, byte len)
+ {
+#if ENABLE_DATA_OUT
+#if STREAM_FORMAT != FORMAT_BIN
+ dispatch(buf, len);
#endif
#endif
+ record(buf, len);
}
- void logData(uint16_t pid, float value1, float value2)
+ void logData(uint16_t pid)
{
-#if LOG_FORMAT == FORMAT_BIN || STREAM_FORMAT == FORMAT_BIN
- LOG_DATA_COMM ld = {dataTime, pid, 2, 0, {value1, value2}};
- ld.checksum = getChecksum((char*)&ld, 16);
-#endif
+ char buf[8];
+ byte len = translatePIDName(pid, buf);
#if ENABLE_DATA_OUT
-#if STREAM_FORMAT == FORMAT_BIN
- SerialBLE.write((uint8_t*)&ld, 16);
-#else
- SerialBLE.print(pid, HEX);
- SerialBLE.write(',');
- SerialBLE.print(value1, 6);
- SerialBLE.write(',');
- SerialBLE.print(value2, 6);
- SerialBLE.write('\n');
+#if STREAM_FORMAT != FORMAT_BIN
+ dispatch(buf, len);
#endif
#endif
-#if ENABLE_DATA_LOG
- if (!sdfile) return;
-#if LOG_FORMAT == FORMAT_BIN
- sdfile.write((uint8_t*)&ld, 16);
- dataSize += 16;
+ record(buf, len);
+ }
+ void logData(uint16_t pid, int16_t value)
+ {
+ char buf[16];
+ byte n = translatePIDName(pid, buf);
+ byte len = sprintf(buf + n, "%d", value) + n;
+#if STREAM_FORMAT == FORMAT_BIN
+ LOG_DATA_COMM ld = {dataTime, pid, 1, 0, value};
+ ld.checksum = getChecksum((char*)&ld, 12);
+ dispatch((const char*)&ld, 12);
#else
- dataSize += sdfile.print(dataTime - m_lastDataTime);
- sdfile.write(',');
- dataSize += sdfile.print(pid, HEX);
- sdfile.write(',');
- dataSize += sdfile.print(value1, 6);
- sdfile.write(',');
- dataSize += sdfile.print(value2, 6);
- sdfile.write('\n');
- dataSize += 4;
- m_lastDataTime = dataTime;
-#endif
+ dispatch(buf, len);
#endif
+ record(buf, len);
}
- void logData(uint16_t pid, uint32_t value1, uint32_t value2)
+ void logData(uint16_t pid, int32_t value)
{
-#if LOG_FORMAT == FORMAT_BIN || STREAM_FORMAT == FORMAT_BIN
- LOG_DATA_COMM ld = {dataTime, pid, 2, 0, {value1, value2}};
- ld.checksum = getChecksum((char*)&ld, 16);
-#endif
+ char buf[20];
+ byte n = translatePIDName(pid, buf);
+ byte len = sprintf(buf + n, "%ld", value) + n;
#if ENABLE_DATA_OUT
#if STREAM_FORMAT == FORMAT_BIN
- SerialBLE.write((uint8_t*)&ld, 16);
-#else
- SerialBLE.print(pid, HEX);
- SerialBLE.write(',');
- SerialBLE.print(value1);
- SerialBLE.write(',');
- SerialBLE.print(value2);
- SerialBLE.write('\n');
-#endif
-#endif
-#if ENABLE_DATA_LOG
- if (!sdfile) return;
-#if LOG_FORMAT == FORMAT_BIN
- sdfile.write((uint8_t*)&ld, 16);
- dataSize += 16;
+ LOG_DATA_COMM ld = {dataTime, pid, 1, 0, value};
+ ld.checksum = getChecksum((char*)&ld, 12);
+ dispatch((const char*)&ld, 12);
#else
- dataSize += sdfile.print(dataTime - m_lastDataTime);
- sdfile.write(',');
- dataSize += sdfile.print(pid, HEX);
- sdfile.write(',');
- dataSize += sdfile.print(value1);
- sdfile.write(',');
- dataSize += sdfile.print(value2);
- sdfile.write('\n');
- dataSize += 4;
- m_lastDataTime = dataTime;
+ dispatch(buf, len);
#endif
#endif
+ record(buf, len);
}
- void logData(uint16_t pid, int value1, int value2, int value3)
+ void logData(uint16_t pid, uint32_t value)
{
-#if LOG_FORMAT == FORMAT_BIN || STREAM_FORMAT == FORMAT_BIN
- LOG_DATA_COMM ld = {dataTime, pid, 3, 0, {value1, value2, value3}};
- ld.checksum = getChecksum((char*)&ld, 20);
-#endif
-#if ENABLE_DATA_OUT
+ char buf[20];
+ byte n = translatePIDName(pid, buf);
+ byte len = sprintf(buf + n, "%lu", value) + n;
#if STREAM_FORMAT == FORMAT_BIN
- SerialBLE.write((uint8_t*)&ld, 20);
+ LOG_DATA_COMM ld = {dataTime, pid, 1, 0, value};
+ ld.checksum = getChecksum((char*)&ld, 12);
+ dispatch((const char*)&ld, 12);
#else
- SerialBLE.print(pid, HEX);
- SerialBLE.write(',');
- SerialBLE.print(value1);
- SerialBLE.write(',');
- SerialBLE.print(value2);
- SerialBLE.write(',');
- SerialBLE.print(value3);
- SerialBLE.write('\n');
+ dispatch(buf, len);
#endif
-#endif
-#if ENABLE_DATA_LOG
- if (!sdfile) return;
-#if LOG_FORMAT == FORMAT_BIN
- sdfile.write((uint8_t*)&ld, 20);
- dataSize += 20;
+ record(buf, len);
+ }
+ void logData(uint16_t pid, int values[])
+ {
+ char buf[24];
+ byte n = translatePIDName(pid, buf);
+ byte len = sprintf(buf + n, "%d,%d,%d", values[0], values[1], values[2]) + n;
+#if STREAM_FORMAT == FORMAT_BIN
+ LOG_DATA_COMM ld = {dataTime, pid, 3, 0, {values[0], values[1], values[2]}};
+ ld.checksum = getChecksum((char*)&ld, 20);
+ dispatch((const char*)&ld, 20);
#else
- dataSize += sdfile.print(dataTime - m_lastDataTime);
- sdfile.write(',');
- dataSize += sdfile.print(pid, HEX);
- sdfile.write(',');
- dataSize += sdfile.print(value1);
- sdfile.write(',');
- dataSize += sdfile.print(value2);
- sdfile.write(',');
- dataSize += sdfile.print(value3);
- sdfile.write('\n');
- dataSize += 5;
- m_lastDataTime = dataTime;
-#endif
+ dispatch(buf, len);
#endif
+ record(buf, len);
}
#if ENABLE_DATA_LOG
uint16_t openFile(uint16_t logFlags = 0, uint32_t dateTime = 0)
{
uint16_t fileIndex;
- char filename[24] = "/FRMATICS";
+ char filename[24] = FILE_PATH;
+ dataSize = 0;
if (SD.exists(filename)) {
for (fileIndex = 1; fileIndex; fileIndex++) {
- sprintf(filename + 9, FILE_NAME_FORMAT, fileIndex);
+ sprintf(filename + sizeof(FILE_PATH) - 1, FILE_NAME_FORMAT, fileIndex);
if (!SD.exists(filename)) {
break;
}
@@ -357,21 +229,14 @@ public:
} else {
SD.mkdir(filename);
fileIndex = 1;
- sprintf(filename + 9, FILE_NAME_FORMAT, 1);
+ sprintf(filename + sizeof(FILE_PATH) - 1, FILE_NAME_FORMAT, 1);
}
sdfile = SD.open(filename, FILE_WRITE);
if (!sdfile) {
return 0;
}
-
-#if LOG_FORMAT == FORMAT_BIN
- HEADER hdr = {'UDUS', HEADER_LEN, 1, 0, logFlags, dateTime};
- sdfile.write((uint8_t*)&hdr, sizeof(hdr));
- for (byte i = 0; i < HEADER_LEN - sizeof(hdr); i++)
- sdfile.write((uint8_t)0);
- dataSize = HEADER_LEN;
-#endif
+ m_lastDataTime = dateTime;
return fileIndex;
}
void closeFile()
@@ -380,13 +245,17 @@ public:
}
void flushFile()
{
- if (sdfile) sdfile.flush();
+ sdfile.flush();
}
#endif
uint32_t dataTime;
uint32_t dataSize;
+#if ENABLE_DATA_CACHE
+ char cache[MAX_CACHE_SIZE];
+ int cacheBytes;
+#endif
private:
- static byte getChecksum(char* buffer, byte len)
+ byte getChecksum(char* buffer, byte len)
{
uint8_t checksum = 0;
for (byte i = 0; i < len; i++) {
@@ -394,10 +263,19 @@ private:
}
return checksum;
}
-#if ENABLE_DATA_LOG
- File sdfile;
-#if LOG_FORMAT == FORMAT_CSV
- uint32_t m_lastDataTime;
-#endif
+ byte translatePIDName(uint16_t pid, char* text)
+ {
+#if STREAM_FORMAT == FORMAT_TEXT && USE_FRIENDLY_PID_NAME
+ for (uint16_t n = 0; n < sizeof(pidNames) / sizeof(pidNames[0]); n++) {
+ uint16_t id = pgm_read_byte(&pidNames[n].pid);
+ if (pid == id) {
+ memcpy_P(text, pidNames[n].name, 3);
+ text[3] = ',';
+ return 4;
+ }
+ }
#endif
+ return sprintf(text, "%X,", pid);
+ }
+ uint32_t m_lastDataTime;
};
diff --git a/esplogger/esplogger.ino b/esplogger/esplogger.ino
index f8895a5..5cc1e7b 100644
--- a/esplogger/esplogger.ino
+++ b/esplogger/esplogger.ino
@@ -1,13 +1,12 @@
/*************************************************************************
-* OBD-II Data Logger based on ESP8266
+* OBD-II Data Logger based on ESP8266 or ESP32
* Distributed under GPL v2.0
-* Developed by Stanley Huang <stanleyhuangyc@gmail.com>
+* Developed by Stanley Huang <support@freematics.com.au>
*************************************************************************/
#include <Arduino.h>
#include <Wire.h>
-#include <OBD.h>
-#include <MPU6050.h>
+#include <OBD2UART.h>
#include "SH1106.h"
#include "images.h"
#include "config.h"
@@ -225,7 +224,7 @@ private:
{
int value = 0;
// send a query to OBD adapter for specified OBD-II pid
- if (read(pid, value)) {
+ if (readPID(pid, value)) {
dataTime = millis();
// log data to SD card
logData(0x100 | pid, value);
@@ -253,7 +252,7 @@ private:
}
if (init()) {
int value;
- if (read(PID_RPM, value) && value > 0)
+ if (readPID(PID_RPM, value) && value > 0)
break;
}
}
@@ -359,9 +358,12 @@ static COBDLogger logger;
void setup()
{
+ Serial.begin(115200);
+ Serial.println("Freematics");
lcd.begin();
lcd.setFontSize(FONT_SIZE_MEDIUM);
lcd.println("ESPLogger");
+ delay(1000);
logger.begin();
logger.initSender();