summaryrefslogtreecommitdiff
path: root/pbox
diff options
context:
space:
mode:
Diffstat (limited to 'pbox')
-rw-r--r--pbox/README.txt11
-rw-r--r--pbox/config.h50
-rw-r--r--pbox/datalogger.h377
-rw-r--r--pbox/images.h5
-rw-r--r--pbox/unologger.cbp600
-rw-r--r--pbox/unologger.depend71
-rw-r--r--pbox/unologger.ino839
7 files changed, 1953 insertions, 0 deletions
diff --git a/pbox/README.txt b/pbox/README.txt
new file mode 100644
index 0000000..217971f
--- /dev/null
+++ b/pbox/README.txt
@@ -0,0 +1,11 @@
+This is the source code for the Arduino OBD-II data logger, which displays (on a 128x64 OLED display module) and records (to a SD card) a selected set of OBD-II data. For hardware configuration and wiring guide, please refer to:
+http://obd.arduinodev.com
+
+The recorded data is stored in CSV format and the file can be illustrated into a graphic chart by a free service at:
+http://freematics.com/chart/
+
+To compile the code with Arduino IDE, please copy all library files from the libraries directory to Arduino's libraries directory.
+
+To open the project file (obdlogger.cbp), please download CodeBlocks Arduino Edition (http://arduinodev.com/codeblocks).
+
+The source code is distributed under GPL license.
diff --git a/pbox/config.h b/pbox/config.h
new file mode 100644
index 0000000..bb026a4
--- /dev/null
+++ b/pbox/config.h
@@ -0,0 +1,50 @@
+#ifndef CONFIG_H_INCLUDED
+#define CONFIG_H_INCLUDED
+
+/**************************************
+* Data logging/streaming out
+**************************************/
+#define ENABLE_DATA_OUT 0
+#define ENABLE_DATA_LOG 1
+#define USE_SOFTSERIAL 0
+//this defines the format of log file
+#define LOG_FORMAT FORMAT_CSV
+
+/**************************************
+* Default working mode
+**************************************/
+#define MODE_DEFAULT MODE_LOGGER /* MODE_LOGGER/MODE_TIMER */
+//#define MODE_SWITCH_PIN 8
+
+/**************************************
+* Choose SD pin here
+**************************************/
+//#define SD_CS_PIN SS // generic
+//#define SD_CS_PIN 4 // ethernet shield
+//#define SD_CS_PIN 7 // microduino
+#define SD_CS_PIN 10 // SD breakout
+
+/**************************************
+* Config GPS here
+**************************************/
+#define USE_GPS 0
+#define GPS_BAUDRATE 38400 /* bps */
+//#define GPS_OPEN_BAUDRATE 4800 /* bps */
+
+/**************************************
+* Choose LCD model here
+**************************************/
+LCD_ILI9341 lcd;
+//LCD_SSD1306 lcd;
+//LCD_Null lcd;
+
+/**************************************
+* Other options
+**************************************/
+#define USE_MPU6050 0
+//#define OBD_MIN_INTERVAL 50 /* ms */
+#define GPS_DATA_TIMEOUT 2000 /* ms */
+//#define DEBUG Serial
+#define DEBUG_BAUDRATE 9600
+
+#endif // CONFIG_H_INCLUDED
diff --git a/pbox/datalogger.h b/pbox/datalogger.h
new file mode 100644
index 0000000..2c4ebfe
--- /dev/null
+++ b/pbox/datalogger.h
@@ -0,0 +1,377 @@
+typedef enum {
+ LOG_TYPE_DEFAULT = 0,
+ LOG_TYPE_0_60,
+ LOG_TYPE_0_100,
+ LOG_TYPE_100_200,
+ LOG_TYPE_400M,
+ LOG_TYPE_LAPS,
+ LOG_TYPE_ROUTE,
+} LOG_TYPES;
+
+#define FLAG_CAR 0x1
+#define FLAG_CYCLING 0x2
+#define FLAG_OBD 0x10
+#define FLAG_GPS 0x20
+#define FLAG_ACC 0x40
+
+#define FORMAT_BIN 0
+#define FORMAT_CSV 1
+
+typedef struct {
+ uint32_t time;
+ uint16_t pid;
+ uint8_t flags;
+ uint8_t checksum;
+ float value;
+} LOG_DATA;
+
+typedef struct {
+ uint32_t time;
+ uint16_t pid;
+ uint8_t flags;
+ uint8_t checksum;
+ 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;
+
+typedef struct {
+ uint32_t time;
+ uint16_t pid;
+ uint8_t message;
+ uint8_t checksum;
+ uint8_t data[12];
+} LOG_DATA_COMMAND;
+
+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 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
+
+#if ENABLE_DATA_OUT && !USE_OBD_BT
+#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
+ SoftwareSerial mySerial(A8, A9); /* for BLE Shield on MEGA*/
+#elif defined(__AVR_ATmega644P__)
+ SoftwareSerial mySerial(9, 10); /* for Microduino */
+#else
+ SoftwareSerial mySerial(A2, A3); /* for BLE Shield on UNO*/
+#endif
+#endif
+
+void btInit(int baudrate);
+void btSend(byte* data, byte length);
+
+class CDataLogger {
+public:
+ void initSender()
+ {
+#if ENABLE_DATA_OUT
+#if USE_OBD_BT
+ btInit(9600);
+#else
+ mySerial.begin(9600);
+#endif
+#endif
+#if ENABLE_DATA_LOG && LOG_FORMAT == FORMAT_CSV
+ m_lastDataTime = 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));
+#if USE_OBD_BT
+ btSend((uint8_t*)&info, sizeof(info));
+#else
+ mySerial.write((uint8_t*)&info, sizeof(info));
+#endif
+ }
+ void sendCommand(byte message, void* data = 0, byte bytes = 0)
+ {
+ LOG_DATA_COMMAND msg = {0, PID_MESSAGE, message};
+ if (data) memcpy(msg.data, data, bytes);
+ msg.checksum = getChecksum((char*)&msg, sizeof(msg));
+#if USE_OBD_BT
+ btSend((uint8_t*)&msg, sizeof(msg));
+#else
+ mySerial.write((uint8_t*)&msg, sizeof(msg));
+#endif
+ }
+ bool receiveCommand(LOG_DATA_COMMAND& msg)
+ {
+#if !USE_OBD_BT
+ if (!mySerial.available())
+ return false;
+
+ if (mySerial.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;
+ }
+#endif
+ return true;
+ }
+#endif
+ void logData(uint16_t pid, int value)
+ {
+ LOG_DATA_COMM ld = {dataTime, pid, 1, 0, value};
+ ld.checksum = getChecksum((char*)&ld, 12);
+#if ENABLE_DATA_OUT
+#if USE_OBD_BT
+ btSend((uint8_t*)&ld, 12);
+#else
+ mySerial.write((uint8_t*)&ld, 12);
+#endif
+#endif
+#if ENABLE_DATA_LOG
+#if LOG_FORMAT == FORMAT_BIN
+ sdfile.write((uint8_t*)&ld, 12);
+ dataSize += 12;
+#else
+ dataSize += sdfile.print(dataTime - m_lastDataTime);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(pid, HEX);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value);
+ dataSize += sdfile.write('\n');
+ m_lastDataTime = dataTime;
+#endif
+#endif
+ }
+ void logData(uint16_t pid, float value)
+ {
+ LOG_DATA_COMM ld = {dataTime, pid, 1, 0, value};
+ ld.checksum = getChecksum((char*)&ld, 12);
+#if ENABLE_DATA_OUT
+#if USE_OBD_BT
+ btSend((uint8_t*)&ld, 12);
+#else
+ mySerial.write((uint8_t*)&ld, 12);
+#endif
+#endif
+#if ENABLE_DATA_LOG
+#if LOG_FORMAT == FORMAT_BIN
+ sdfile.write((uint8_t*)&ld, 12);
+ dataSize += 12;
+#else
+ dataSize += sdfile.print(dataTime - m_lastDataTime);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(pid, HEX);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value);
+ dataSize += sdfile.write('\n');
+ m_lastDataTime = dataTime;
+#endif
+#endif
+ }
+ void logData(uint16_t pid, float value1, float value2)
+ {
+ LOG_DATA_COMM ld = {dataTime, pid, 2, 0, {value1, value2}};
+ ld.checksum = getChecksum((char*)&ld, 16);
+#if ENABLE_DATA_OUT
+#if USE_OBD_BT
+ btSend((uint8_t*)&ld, 16);
+#else
+ mySerial.write((uint8_t*)&ld, 16);
+#endif
+#endif
+#if ENABLE_DATA_LOG
+#if LOG_FORMAT == FORMAT_BIN
+ sdfile.write((uint8_t*)&ld, 16);
+ dataSize += 16;
+#else
+ dataSize += sdfile.print(dataTime - m_lastDataTime);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(pid, HEX);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value1, 6);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value2, 6);
+ dataSize += sdfile.write('\n');
+ m_lastDataTime = dataTime;
+#endif
+#endif
+ }
+ void logData(uint16_t pid, uint32_t value1, uint32_t value2)
+ {
+ LOG_DATA_COMM ld = {dataTime, pid, 2, 0, {value1, value2}};
+ ld.checksum = getChecksum((char*)&ld, 16);
+#if ENABLE_DATA_OUT
+#if USE_OBD_BT
+ btSend((uint8_t*)&ld, 16);
+#else
+ mySerial.write((uint8_t*)&ld, 16);
+#endif
+#endif
+#if ENABLE_DATA_LOG
+#if LOG_FORMAT == FORMAT_BIN
+ sdfile.write((uint8_t*)&ld, 16);
+ dataSize += 16;
+#else
+ dataSize += sdfile.print(dataTime - m_lastDataTime);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(pid, HEX);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value1);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value2);
+ dataSize += sdfile.write('\n');
+ m_lastDataTime = dataTime;
+#endif
+#endif
+ }
+ void logData(uint16_t pid, int value1, int value2, int value3)
+ {
+ LOG_DATA_COMM ld = {dataTime, pid, 3, 0, {value1, value2, value3}};
+ ld.checksum = getChecksum((char*)&ld, 20);
+#if ENABLE_DATA_OUT
+#if USE_OBD_BT
+ btSend((uint8_t*)&ld, 20);
+#else
+ mySerial.write((uint8_t*)&ld, 20);
+#endif
+#endif
+#if ENABLE_DATA_LOG
+#if LOG_FORMAT == FORMAT_BIN
+ sdfile.write((uint8_t*)&ld, 20);
+ dataSize += 20;
+#else
+ dataSize += sdfile.print(dataTime - m_lastDataTime);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(pid, HEX);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value1);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value2);
+ dataSize += sdfile.write(',');
+ dataSize += sdfile.print(value3);
+ dataSize += sdfile.write('\n');
+ m_lastDataTime = dataTime;
+#endif
+#endif
+ }
+#if ENABLE_DATA_LOG
+ uint16_t openFile(LOG_TYPES logType, uint16_t logFlags = 0, uint32_t dateTime = 0)
+ {
+ uint16_t fileIndex;
+ char filename[24] = "/FRMATICS";
+
+ if (SD.exists(filename)) {
+ for (fileIndex = 1; fileIndex; fileIndex++) {
+ sprintf(filename + 9, FILE_NAME_FORMAT, fileIndex);
+ if (!SD.exists(filename)) {
+ break;
+ }
+ }
+ if (fileIndex == 0)
+ return 0;
+ } else {
+ SD.mkdir(filename);
+ fileIndex = 1;
+ sprintf(filename + 9, 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, logType, 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
+ return fileIndex;
+ }
+ void closeFile()
+ {
+ sdfile.close();
+ }
+ void flushFile()
+ {
+ sdfile.flush();
+ }
+#endif
+ uint32_t dataTime;
+ uint32_t dataSize;
+private:
+ static byte getChecksum(char* buffer, byte len)
+ {
+ uint8_t checksum = 0;
+ for (byte i = 0; i < len; i++) {
+ checksum ^= buffer[i];
+ }
+ return checksum;
+ }
+#if ENABLE_DATA_LOG
+ File sdfile;
+#if LOG_FORMAT == FORMAT_CSV
+ uint32_t m_lastDataTime;
+#endif
+#endif
+};
diff --git a/pbox/images.h b/pbox/images.h
new file mode 100644
index 0000000..0a0f0b6
--- /dev/null
+++ b/pbox/images.h
@@ -0,0 +1,5 @@
+const PROGMEM uint8_t tick[16 *16 / 8] =
+{0x00,0x80,0xC0,0xE0,0xC0,0x80,0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0x78,0x30,0x00,0x00,0x01,0x03,0x07,0x0F,0x1F,0x1F,0x1F,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00};
+
+const PROGMEM uint8_t cross[16 *16 / 8] =
+{0x00,0x0C,0x1C,0x3C,0x78,0xF0,0xE0,0xC0,0xE0,0xF0,0x78,0x3C,0x1C,0x0C,0x00,0x00,0x00,0x30,0x38,0x3C,0x1E,0x0F,0x07,0x03,0x07,0x0F,0x1E,0x3C,0x38,0x30,0x00,0x00};
diff --git a/pbox/unologger.cbp b/pbox/unologger.cbp
new file mode 100644
index 0000000..1058588
--- /dev/null
+++ b/pbox/unologger.cbp
@@ -0,0 +1,600 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+ <FileVersion major="1" minor="6" />
+ <Project>
+ <Option title="obdlogger" />
+ <Option pch_mode="2" />
+ <Option compiler="avrgcc" />
+ <Build>
+ <Target title="Simulator">
+ <Option output="bin/Release/obdlogger_sim.exe" prefix_auto="1" extension_auto="0" />
+ <Option object_output="obj/Release/" />
+ <Option type="1" />
+ <Option compiler="GCC" />
+ <Compiler>
+ <Add option="-Os" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-DARDUSIM" />
+ <Add option="-D__AVR_ATmega2560__" />
+ <Add option="-x c++" />
+ <Add directory="$(ARDUINO_DIR)/arduino/cores" />
+ <Add directory="$(ARDUINO_DIR)/arduino/variants/standard" />
+ <Add directory="$(ARDUINO_DIR)/include" />
+ </Compiler>
+ <Linker>
+ <Add option="-lardusim" />
+ </Linker>
+ <Environment>
+ <Variable name="ARDUINO_DIR" value="$(APP_PATH)\ardusim" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Uno">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-Os" />
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega328P__" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/standard" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Uno" />
+ <Variable name="BOARD_ID" value="uno" />
+ <Variable name="MCU" value="atmega328p" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="115200" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Leonardo">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega32U4__" />
+ <Add option="-DUSB_VID=0x2341" />
+ <Add option="-DUSB_PID=0x8036" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/leonardo" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Leonardo" />
+ <Variable name="BOARD_ID" value="leonardo" />
+ <Variable name="MCU" value="atmega32u4" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Esplora">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega32U4__" />
+ <Add option="-DUSB_VID=0x2341" />
+ <Add option="-DUSB_PID=0x8037" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/leonardo" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Esplora" />
+ <Variable name="BOARD_ID" value="esplora" />
+ <Variable name="MCU" value="atmega32u4" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Micro">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega32U4__" />
+ <Add option="-DUSB_VID=0x2341" />
+ <Add option="-DUSB_PID=0x803C" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/micro" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Micro" />
+ <Variable name="BOARD_ID" value="micro" />
+ <Variable name="MCU" value="atmega32u4" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Duemilanove (328)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega328P__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/standard" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Duemilanove (328)" />
+ <Variable name="BOARD_ID" value="duemilanove328" />
+ <Variable name="MCU" value="atmega328p" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Duemilanove (168)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega168__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/standard" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Duemilanove (168)" />
+ <Variable name="BOARD_ID" value="duemilanove168" />
+ <Variable name="MCU" value="atmega168" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="19200" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Nano (328)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega328P__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/eightanaloginputs" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Nano (328)" />
+ <Variable name="BOARD_ID" value="nano328" />
+ <Variable name="MCU" value="atmega328p" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Nano (168)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega168__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/eightanaloginputs" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Nano (168)" />
+ <Variable name="BOARD_ID" value="nano168" />
+ <Variable name="MCU" value="atmega168" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="19200" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Mini (328)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega328P__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/eightanaloginputs" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Mini (328)" />
+ <Variable name="BOARD_ID" value="mini328" />
+ <Variable name="MCU" value="atmega328p" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Mini (168)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega168__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/eightanaloginputs" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Mini (168)" />
+ <Variable name="BOARD_ID" value="mini168" />
+ <Variable name="MCU" value="atmega168" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="19200" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Pro Mini (328)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega328P__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/standard" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Pro Mini (328)" />
+ <Variable name="BOARD_ID" value="promini328" />
+ <Variable name="MCU" value="atmega328p" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Pro Mini (168)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega168__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/standard" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Pro Mini (168)" />
+ <Variable name="BOARD_ID" value="promini168" />
+ <Variable name="MCU" value="atmega168" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="19200" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Mega 2560/ADK">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-O3" />
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega2560__" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/mega" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Mega 2560\ADK" />
+ <Variable name="BOARD_ID" value="mega2560" />
+ <Variable name="MCU" value="atmega2560" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="115200" />
+ <Variable name="UPLOAD_PORT" value="COM37" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Mega 1280">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega1280__" />
+ <Add option="-O2" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/mega" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Mega 1280" />
+ <Variable name="BOARD_ID" value="mega1280" />
+ <Variable name="MCU" value="atmega1280" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="57600" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Arduino Mega 8">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega328P__" />
+ <Add option="-Os" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/standard" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Arduino Mega 8" />
+ <Variable name="BOARD_ID" value="mega8" />
+ <Variable name="MCU" value="atmega8" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="19200" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ <Target title="Microduino Core+ (644P)">
+ <Option output="bin/Release/obdlogger_${BOARD_ID}.elf" prefix_auto="1" extension_auto="0" />
+ <Option type="1" />
+ <Option compiler="avrgcc" />
+ <Compiler>
+ <Add option="-O3" />
+ <Add option="-x c++" />
+ <Add option="-mmcu=$(MCU)" />
+ <Add option="-DF_CPU=16000000L" />
+ <Add option="-D__AVR_ATmega644P__" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/cores/arduino" />
+ <Add directory="$(ARDUINO_DIR)/libraries" />
+ <Add directory="$(ARDUINO_DIR)/hardware/arduino/variants/plus" />
+ </Compiler>
+ <Linker>
+ <Add option="-mmcu=$(MCU)" />
+ <Add option='&quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add option='&quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ </Linker>
+ <ExtraCommands>
+ <Add before='$(TARGET_COMPILER_DIR)ArduinoUploader &quot;$(PROJECT_DIR).&quot; $(BOARD_ID) - $(MCU_CLOCK) 0 &quot;$(PROJECT_DIR)bin/lib_${BOARD_ID}_${MCU_CLOCK}.a&quot; &quot;$(PROJECT_DIR)bin/core_${BOARD_ID}_${MCU_CLOCK}.a&quot;' />
+ <Add after='avr-objcopy -O ihex -R .eeprom -R .eesafe &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).hex&quot;' />
+ <Add after='avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex &quot;$(TARGET_OUTPUT_FILE)&quot; &quot;$(TARGET_OUTPUT_FILE).eep.hex&quot;' />
+ <Add after='avr-size --mcu=$(MCU) --format=avr &quot;$(TARGET_OUTPUT_FILE)&quot;' />
+ </ExtraCommands>
+ <Environment>
+ <Variable name="BOARD" value="Microduino Core+ (644P)" />
+ <Variable name="BOARD_ID" value="uduino644p" />
+ <Variable name="MCU" value="atmega644p" />
+ <Variable name="MCU_CLOCK" value="16" />
+ <Variable name="UPLOAD_BAUDRATE" value="115200" />
+ <Variable name="UPLOAD_PORT" value="" />
+ </Environment>
+ </Target>
+ </Build>
+ <Compiler>
+ <Add directory="." />
+ </Compiler>
+ <Unit filename="MicroLCD.cpp" />
+ <Unit filename="MicroLCD.h" />
+ <Unit filename="SH1106.cpp" />
+ <Unit filename="config.h" />
+ <Unit filename="datalogger.h" />
+ <Unit filename="images.h" />
+ <Unit filename="obdlogger.ino">
+ <Option compile="1" />
+ <Option link="1" />
+ </Unit>
+ <Extensions>
+ <code_completion />
+ <debugger />
+ </Extensions>
+ </Project>
+</CodeBlocks_project_file>
diff --git a/pbox/unologger.depend b/pbox/unologger.depend
new file mode 100644
index 0000000..e2b660f
--- /dev/null
+++ b/pbox/unologger.depend
@@ -0,0 +1,71 @@
+# depslib dependency file v1.0
+1394102826 source:e:\arduino\arduinoobd\unologger\unologger.ino
+ <Arduino.h>
+ <Wire.h>
+ <OBD.h>
+ <SPI.h>
+ <SD.h>
+ <MPU6050.h>
+ "MultiLCD.h"
+ "images.h"
+ "config.h"
+ <SoftwareSerial.h>
+ "datalogger.h"
+ <TinyGPS.h>
+
+1371033101 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\arduino.h
+ <stdlib.h>
+ <string.h>
+ <math.h>
+ <avr/pgmspace.h>
+ <avr/io.h>
+ <avr/interrupt.h>
+ "binary.h"
+ "WCharacter.h"
+ "WString.h"
+ "HardwareSerial.h"
+ "pins_arduino.h"
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\binary.h
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\wcharacter.h
+ <ctype.h>
+
+1371033133 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\wstring.h
+ <stdlib.h>
+ <string.h>
+ <ctype.h>
+ <avr/pgmspace.h>
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\hardwareserial.h
+ <inttypes.h>
+ "Stream.h"
+ "USBAPI.h"
+
+1371032829 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\stream.h
+ <inttypes.h>
+ "Print.h"
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\print.h
+ <inttypes.h>
+ <stdio.h>
+ "WString.h"
+ "Printable.h"
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\printable.h
+ <new.h>
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\new.h
+ <stdlib.h>
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\cores\arduino\usbapi.h
+
+1362986950 d:\apps\codeblocks\arduino\hardware\arduino\variants\standard\pins_arduino.h
+ <avr/pgmspace.h>
+
+1391012219 e:\arduino\arduinoobd\unologger\images.h
+
+1394102939 e:\arduino\arduinoobd\unologger\config.h
+
+1391012219 e:\arduino\arduinoobd\unologger\datalogger.h
+
diff --git a/pbox/unologger.ino b/pbox/unologger.ino
new file mode 100644
index 0000000..fbca988
--- /dev/null
+++ b/pbox/unologger.ino
@@ -0,0 +1,839 @@
+/*************************************************************************
+* Arduino GPS/OBD-II/G-Force Data Logger
+* Distributed under GPL v2.0
+* Copyright (c) 2013 Stanley Huang <stanleyhuangyc@gmail.com>
+* All rights reserved.
+*************************************************************************/
+
+#include <Arduino.h>
+#include <Wire.h>
+#include <OBD.h>
+#include <SPI.h>
+#include <SD.h>
+#include <MPU6050.h>
+#include "MultiLCD.h"
+#include "images.h"
+#include "config.h"
+#if USE_SOFTSERIAL
+#include <SoftwareSerial.h>
+#endif
+#include "datalogger.h"
+
+// logger states
+#define STATE_SD_READY 0x1
+#define STATE_OBD_READY 0x2
+#define STATE_GPS_FOUND 0x4
+#define STATE_GPS_READY 0x8
+#define STATE_ACC_READY 0x10
+#define STATE_SLEEPING 0x20
+
+#define MODE_LOGGER 0
+#define MODE_TIMER 1
+
+#if USE_GPS
+// GPS logging can only be enabled when there is additional hardware serial UART
+#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
+#define GPSUART Serial2
+#elif defined(__AVR_ATmega644P__)
+#define GPSUART Serial
+#endif
+
+#ifdef GPSUART
+
+#include <TinyGPS.h>
+
+#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F"
+#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C"
+#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F"
+#define PMTK_SET_NMEA_OUTPUT_ALLDATA "$PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28"
+#define PMTK_SET_BAUDRATE "$PMTK251,115200*1F"
+
+TinyGPS gps;
+
+static long lastLat = 0;
+static long lastLon = 0;
+static long curLat = 0;
+static long curLon = 0;
+static uint32_t lastGPSDataTime = 0;
+static uint16_t speedGPS = 0;
+
+#endif // GPSUART
+#endif
+
+static uint32_t lastFileSize = 0;
+static int lastSpeed = -1;
+static uint32_t lastSpeedTime = 0;
+static int speed = 0;
+static uint32_t distance = 0;
+static uint16_t fileIndex = 0;
+static uint32_t startTime = 0;
+
+#define STAGE_IDLE 0
+#define STAGE_WAIT_START 1
+#define STAGE_MEASURING 2
+
+static byte mode = MODE_DEFAULT;
+static byte stage = STAGE_IDLE;
+
+#define SPEED_THRESHOLD_1 60 /* kph */
+#define SPEED_THRESHOLD_2 100 /* kph */
+#define SPEED_THRESHOLD_3 200 /* kph */
+#define DISTANCE_THRESHOLD 400 /* meters */
+
+static uint16_t times[4] = {0};
+
+static byte pidTier1[]= {PID_RPM, PID_SPEED, PID_ENGINE_LOAD, PID_THROTTLE};
+static byte pidTier2[] = {PID_INTAKE_MAP, PID_MAF_FLOW, PID_TIMING_ADVANCE};
+static byte pidTier3[] = {PID_COOLANT_TEMP, PID_INTAKE_TEMP, PID_AMBIENT_TEMP, PID_FUEL_LEVEL};
+
+#define TIER_NUM1 sizeof(pidTier1)
+#define TIER_NUM2 sizeof(pidTier2)
+#define TIER_NUM3 sizeof(pidTier3)
+
+class COBDLogger : public COBD, public CDataLogger
+{
+public:
+ COBDLogger():state(0) {}
+ void setup()
+ {
+#if USE_GPS
+ lastGPSDataTime = 0;
+#endif
+ showStates();
+
+#if USE_MPU6050
+ Wire.begin();
+ if (MPU6050_init() == 0) {
+ state |= STATE_ACC_READY;
+ showStates();
+ }
+#endif
+
+#ifdef GPSUART
+ unsigned long t = millis();
+ do {
+ if (GPSUART.available()) {
+ char c = GPSUART.read();
+ if (c == '\r') {
+ state |= STATE_GPS_FOUND;
+ break;
+ }
+ }
+ } while (millis() - t <= 5000);
+#endif
+
+ do {
+ showStates();
+ } while (!init());
+
+ state |= STATE_OBD_READY;
+
+ showStates();
+
+ uint16_t flags = FLAG_CAR | FLAG_OBD;
+ if (state & STATE_GPS_FOUND) flags |= FLAG_GPS;
+ if (state & STATE_ACC_READY) flags |= FLAG_ACC;
+#if ENABLE_DATA_LOG
+ uint16_t index = openFile(LOG_TYPE_DEFAULT, flags);
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(86, 0);
+ if (index) {
+ lcd.write('[');
+ lcd.setFlags(FLAG_PAD_ZERO);
+ lcd.printInt(index, 5);
+ lcd.setFlags(0);
+ lcd.write(']');
+ } else {
+ lcd.print("NO LOG");
+ }
+ delay(100);
+#endif
+
+#ifndef MEMORY_SAVING
+ //showECUCap();
+ //delay(1000);
+#endif
+
+#if ENABLE_DATA_LOG
+ // open file for logging
+ if (!(state & STATE_SD_READY)) {
+ if (checkSD()) {
+ state |= STATE_SD_READY;
+ showStates();
+ }
+ }
+#endif
+
+ initScreen();
+ }
+ void loop()
+ {
+ static byte index = 0;
+ static byte index2 = 0;
+ static byte index3 = 0;
+
+#ifdef GPSUART
+ if (millis() - lastGPSDataTime > GPS_DATA_TIMEOUT || gps.satellites() < 3) {
+ // GPS not ready
+ state &= ~STATE_GPS_READY;
+ } else {
+ // GPS ready
+ state |= STATE_GPS_READY;
+ }
+#endif
+
+
+ if (mode == MODE_TIMER) {
+ timerLoop();
+ } else {
+ logOBDData(pidTier1[index++]);
+ if (index == TIER_NUM1) {
+ index = 0;
+ if (index2 == TIER_NUM2) {
+ index2 = 0;
+ logOBDData(pidTier3[index3]);
+ index3 = (index3 + 1) % TIER_NUM3;
+ } else {
+ logOBDData(pidTier2[index2++]);
+ }
+ }
+
+ char buf[10];
+ sprintf(buf, "%4ukm", (uint16_t)(distance / 1000));
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(92, 6);
+ lcd.print(buf);
+
+#if USE_MPU6050
+ if (state & STATE_ACC_READY) {
+ processAccelerometer();
+ }
+#endif
+ }
+
+#if ENABLE_DATA_LOG
+ // flush SD data every 1KB
+ if (dataSize - lastFileSize >= 1024 && stage != STAGE_MEASURING) {
+ flushFile();
+ lastFileSize = dataSize;
+ // display logged data size
+ if (mode == MODE_LOGGER) {
+ char buf[7];
+ sprintf(buf, "%4uKB", (int)(dataSize >> 10));
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(92, 7);
+ lcd.print(buf);
+ }
+ }
+#endif
+
+ if (errors >= 2) {
+ reconnect();
+ }
+ }
+#if ENABLE_DATA_LOG
+ bool checkSD()
+ {
+ Sd2Card card;
+ SdVolume volume;
+ lcd.setCursor(0, 0);
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ state &= ~STATE_SD_READY;
+ pinMode(SS, OUTPUT);
+ if (card.init(SPI_HALF_SPEED, SD_CS_PIN)) {
+ const char* type;
+ char buf[20];
+
+ switch(card.type()) {
+ case SD_CARD_TYPE_SD1:
+ type = "SD1";
+ break;
+ case SD_CARD_TYPE_SD2:
+ type = "SD2";
+ break;
+ case SD_CARD_TYPE_SDHC:
+ type = "SDHC";
+ break;
+ default:
+ type = "SDx";
+ }
+
+ lcd.clear();
+ lcd.print(type);
+ lcd.write(' ');
+ if (!volume.init(card)) {
+ lcd.print("No FAT!");
+ return false;
+ }
+
+ uint32_t volumesize = volume.blocksPerCluster();
+ volumesize >>= 1; // 512 bytes per block
+ volumesize *= volume.clusterCount();
+ volumesize >>= 10;
+
+ sprintf(buf, "%dGB", (int)((volumesize + 511) / 1000));
+ lcd.print(buf);
+ } else {
+ lcd.clear();
+ lcd.print("SD");
+ lcd.draw(cross, 32, 0, 16, 16);
+ return false;
+ }
+
+ if (!SD.begin(SD_CS_PIN)) {
+ lcd.setCursor(48, 0);
+ lcd.print("Bad SD");
+ return false;
+ }
+
+ state |= STATE_SD_READY;
+ return true;
+ }
+#endif
+ void initScreen()
+ {
+ if (mode == MODE_LOGGER)
+ initLoggerScreen();
+ else
+ initTimerScreen();
+ }
+private:
+ void dataIdleLoop()
+ {
+ if (state & STATE_SLEEPING) return;
+
+#ifdef GPSUART
+ // detect GPS signal
+ if (GPSUART.available())
+ processGPS();
+
+ if (lastGPSDataTime) {
+ state |= STATE_GPS_READY;
+ }
+#endif
+
+ if (getState() == OBD_CONNECTED)
+ return;
+
+ // called while initializing
+ char buf[10];
+ unsigned int t = (millis() - startTime) / 1000;
+ sprintf(buf, "%02u:%02u", t / 60, t % 60);
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(97, 7);
+ lcd.print(buf);
+#if USE_MPU6050
+ if (state & STATE_ACC_READY) {
+ accel_t_gyro_union data;
+ MPU6050_readout(&data);
+ char buf[8];
+ lcd.setFont(FONT_SIZE_SMALL);
+ int temp = (data.value.temperature + 12412) / 340;
+ sprintf(buf, "TEMP%3dC", temp);
+ lcd.setCursor(80, 2);
+ lcd.print(buf);
+
+ sprintf(buf, "AX%3d", data.value.x_accel / 160);
+ lcd.setCursor(98, 3);
+ lcd.print(buf);
+ sprintf(buf, "AY%3d", data.value.y_accel / 160);
+ lcd.setCursor(98, 4);
+ lcd.print(buf);
+ sprintf(buf, "AZ%3d", data.value.z_accel / 160);
+ lcd.setCursor(98, 5);
+ lcd.print(buf);
+
+ sprintf(buf, "GX%3d", data.value.x_gyro / 256);
+ lcd.setCursor(64, 3);
+ lcd.print(buf);
+ sprintf(buf, "GY%3d", data.value.y_gyro / 256);
+ lcd.setCursor(64, 4);
+ lcd.print(buf);
+ sprintf(buf, "GZ%3d", data.value.z_gyro / 256);
+ lcd.setCursor(64, 5);
+ lcd.print(buf);
+ //delay(50);
+ }
+#endif
+ }
+#ifdef GPSUART
+ void processGPS()
+ {
+ // process GPS data
+ char c = GPSUART.read();
+ if (!gps.encode(c))
+ return;
+
+ // parsed GPS data is ready
+ static uint32_t lastAltTime = 0;
+
+ dataTime = millis();
+
+ speedGPS = (uint16_t)(gps.speed() * 1852 / 100);
+ if (speedGPS > 1000) speedGPS = 0;
+ logData(PID_GPS_SPEED, speedGPS);
+
+ // no need to log GPS data when vehicle has not been moving
+ // that's when previous speed is zero and current speed is also zero
+ byte sat = gps.satellites();
+ if (sat >= 3 && sat < 100) {
+ // lastSpeed will be updated
+ //ShowSensorData(PID_SPEED, speed);
+
+ gps.get_position(&curLat, &curLon, 0);
+
+ // calclate distance
+ if (lastLat) {
+ int16_t latDiff = curLat - lastLat;
+ int16_t lonDiff = curLon - lastLon;
+ distance = sqrt(latDiff * latDiff + lonDiff * lonDiff);
+ }
+
+ logData(PID_GPS_COORDINATES, (float)curLat / 100000, (float)curLon / 100000);
+
+ if (dataTime - lastAltTime > 10000) {
+ uint32_t time;
+ uint32_t date;
+ gps.get_datetime(&date, &time, 0);
+ logData(PID_GPS_TIME, time, date);
+ logData(PID_GPS_ALTITUDE, (float)gps.altitude());
+ }
+
+ if (mode == MODE_LOGGER) {
+ lcd.setFont(FONT_SIZE_SMALL);
+ if (((unsigned int)dataTime >> 11) & 1) {
+ char buf[16];
+ sprintf(buf, "LAT:%d.%05ld ", (int)(curLat / 100000), curLat % 100000);
+ lcd.setCursor(0, 6);
+ lcd.print(buf);
+ sprintf(buf, "LON:%d.%05ld ", (int)(curLon / 100000), curLon % 100000);
+ lcd.setCursor(0, 7);
+ lcd.print(buf);
+ } else {
+ char buf[16];
+ lcd.setCursor(0, 6);
+ sprintf(buf, "SAT:%u ", (unsigned int)sat);
+ lcd.print(buf);
+ lcd.setCursor(0, 7);
+ uint32_t time;
+ gps.get_datetime(0, &time, 0);
+ sprintf(buf, "TIME:%08ld ", time);
+ lcd.print(buf);
+ }
+ }
+ }
+ lastGPSDataTime = dataTime;
+ }
+#endif
+#if USE_MPU6050
+ void processAccelerometer()
+ {
+ accel_t_gyro_union data;
+ MPU6050_readout(&data);
+ dataTime = millis();
+ // log x/y/z of accelerometer
+ logData(PID_ACC, data.value.x_accel, data.value.y_accel, data.value.z_accel);
+ //showGForce(data.value.y_accel);
+ // log x/y/z of gyro meter
+ logData(PID_GYRO, data.value.x_gyro, data.value.y_gyro, data.value.z_gyro);
+
+#ifdef DEBUG
+ DEBUG.print(dataTime);
+ DEBUG.print(" X:");
+ DEBUG.print(data.value.x_accel);
+ DEBUG.print(" Y:");
+ DEBUG.print(data.value.y_accel);
+ DEBUG.print(" Z:");
+ DEBUG.println(data.value.z_accel);
+#endif
+ }
+#endif
+ void logOBDData(byte pid)
+ {
+ int value;
+#ifdef OBD_MIN_INTERVAL
+ uint32_t start = millis();
+#endif
+
+ // send a query to OBD adapter for specified OBD-II pid
+ if (read(pid, value)) {
+ dataTime = millis();
+ showLoggerData(pid, value);
+ // log data to SD card
+ logData(0x100 | pid, value);
+ }
+
+ // if OBD response is very fast, go on processing other data for a while
+#ifdef OBD_MIN_INTERVAL
+ while (millis() - start < OBD_MIN_INTERVAL) {
+ dataIdleLoop();
+ }
+#endif
+ }
+ void timerLoop()
+ {
+ uint32_t elapsed = millis() - startTime;
+ uint16_t n;
+
+ int speed;
+ if (!read(PID_SPEED, speed))
+ return;
+
+ dataTime = millis();
+
+ lcd.setFont(FONT_SIZE_XLARGE);
+ if (lastSpeed != speed) {
+ lcd.setCursor(0, 4);
+ lcd.printInt((unsigned int)speed % 1000, 3);
+ lastSpeed = speed;
+ }
+
+ if (!(state & STATE_GPS_READY)) {
+ // estimate distance
+ distance += (uint32_t)(speed + lastSpeed) * (dataTime - lastSpeedTime) / 2 / 3600;
+ }
+ lastSpeedTime = dataTime;
+
+ if (stage == STAGE_WAIT_START) {
+ if (speed > 0) {
+ stage = STAGE_MEASURING;
+ startTime = lastSpeedTime;
+
+ uint32_t t = dataTime;
+ dataTime = lastSpeedTime;
+ logData(0x100 | PID_SPEED, lastSpeed);
+ dataTime = t;
+ logData(0x100 | PID_SPEED, speed);
+
+#if USE_GPS
+ lastLat = curLat;
+ lastLon = curLon;
+#endif
+ lastSpeed = 0;
+ distance = 0;
+
+ memset(times, 0, sizeof(times));
+
+ initTimerScreen();
+ }
+ } else if (stage == STAGE_MEASURING) {
+ // display elapsed time (mm:ss:mm)
+ n = elapsed / 1000;
+ if (n < 100) {
+ lcd.setCursor(0, 0);
+ lcd.printInt(n, 2);
+ n = (elapsed % 1000) / 100;
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ lcd.setCursor(32, 1);
+ lcd.write('.');
+ lcd.write('0' + n);
+ }
+#if USE_GPS
+ if (speedGPS > speed) speed = speedGPS;
+#endif
+ if (times[2] == 0 && speed >= SPEED_THRESHOLD_3) {
+ times[2] = elapsed / 100;
+ stage = STAGE_IDLE;
+ lcd.clearLine(0);
+ lcd.clearLine(1);
+ lcd.clearLine(2);
+ showTimerResults();
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ lcd.setCursor(0, 0);
+ lcd.print("DONE!");
+ } else if (times[1] == 0 && speed >= SPEED_THRESHOLD_2) {
+ times[1] = elapsed / 100;
+ showTimerResults();
+ } else if (times[0] == 0 && speed >= SPEED_THRESHOLD_1) {
+ times[0] = elapsed / 100;
+ showTimerResults();
+ } else if (speed == 0) {
+ // speed go back to 0
+ stage = STAGE_IDLE;
+ }
+ if (distance > 0) {
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(62, 6);
+ if (distance >= 400) {
+ lcd.printInt(400, 3);
+ if (!times[3]) {
+ times[3] = elapsed / 100;
+ showTimerResults();
+ }
+ } else {
+ lcd.printInt(distance, 3);
+ }
+ }
+ // log speed data
+ logData(0x100 | PID_SPEED, speed);
+ // log additional data
+ int rpm;
+ if (read(PID_RPM, rpm)) {
+ dataTime = millis();
+ logData(0x100 | PID_RPM, rpm);
+ }
+ } else {
+ if (speed == 0) {
+ stage = STAGE_WAIT_START;
+ initTimerScreen();
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ lcd.setCursor(0, 0);
+ lcd.println(" GET");
+ lcd.println("READY");
+ delay(500);
+ }
+ }
+ }
+#ifndef MEMORY_SAVING
+ void showECUCap()
+ {
+ char buffer[24];
+ byte pidlist[] = {PID_RPM, PID_SPEED, PID_THROTTLE, PID_ENGINE_LOAD, PID_CONTROL_MODULE_VOLTAGE, PID_MAF_FLOW, PID_INTAKE_MAP, PID_FUEL_LEVEL, PID_FUEL_PRESSURE, PID_COOLANT_TEMP, PID_INTAKE_TEMP, PID_AMBIENT_TEMP, PID_TIMING_ADVANCE, PID_BAROMETRIC};
+ const char* namelist[] = {"RPM", "SPEED", "THROTTLE", "ENG.LOAD", "CTRL VOLT", "MAF", "MAP", "FUEL LV.", "FUEL PRE.", "COOLANT", "INTAKE","AMBIENT", "IGNITION", "BARO"};
+ byte i = 0;
+ lcd.clear();
+ lcd.setFont(FONT_SIZE_SMALL);
+ for (; i < sizeof(pidlist) / sizeof(pidlist[0]) / 2; i++) {
+ lcd.setCursor(0, i);
+ sprintf(buffer, "%s:%c", namelist[i], isValidPID(pidlist[i]) ? 'Y' : 'N');
+ lcd.print(buffer);
+ }
+ for (byte row = 0; i < sizeof(pidlist) / sizeof(pidlist[0]); i++, row++) {
+ lcd.setCursor(64, row);
+ sprintf(buffer, "%s:%c", namelist[i], isValidPID(pidlist[i]) ? 'Y' : 'N');
+ lcd.print(buffer);
+ }
+ }
+#endif
+ void reconnect()
+ {
+#if ENABLE_DATA_LOG
+ closeFile();
+#endif
+ lcd.clear();
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ lcd.print("Reconnecting");
+ startTime = millis();
+ state &= ~(STATE_OBD_READY | STATE_ACC_READY);
+ state |= STATE_SLEEPING;
+ //digitalWrite(SD_CS_PIN, LOW);
+ for (int i = 0; !init(); i++) {
+ if (i == 10) lcd.clear();
+ }
+ state &= ~STATE_SLEEPING;
+ fileIndex++;
+ write('\r');
+ setup();
+ }
+ byte state;
+
+ // screen layout related stuff
+ void showStates()
+ {
+#ifdef DEBUG
+ DEBUG.print(millis());
+ DEBUG.print(" OBD:");
+ DEBUG.print((state & STATE_OBD_READY) ? 'Y' : 'N');
+ DEBUG.print(" ACC:");
+ DEBUG.print((state & STATE_ACC_READY) ? 'Y' : 'N');
+ DEBUG.print(" GPS:");
+ DEBUG.println((state & STATE_GPS_FOUND) ? 'Y' : 'N');
+#endif // DEBUG
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ lcd.setCursor(0, 2);
+ lcd.print("OBD");
+ lcd.draw((state & STATE_OBD_READY) ? tick : cross, 32, 16, 16, 16);
+ lcd.setCursor(0, 4);
+ lcd.print("ACC");
+ lcd.draw((state & STATE_ACC_READY) ? tick : cross, 32, 32, 16, 16);
+ lcd.setCursor(0, 6);
+ if (!(state & STATE_GPS_READY)) {
+ lcd.print("GPS");
+ lcd.draw((state & STATE_GPS_FOUND) ? tick : cross, 32, 48, 16, 16);
+ }
+ }
+ void showLoggerData(byte pid, int value)
+ {
+#ifdef DEBUG
+ DEBUG.print(millis());
+ DEBUG.print(" PID[");
+ DEBUG.print(pid, HEX);
+ DEBUG.print("]=");
+ DEBUG.println(value);
+#endif
+ char buf[8];
+ switch (pid) {
+ case PID_RPM:
+ lcd.setCursor(64, 0);
+ lcd.setFont(FONT_SIZE_XLARGE);
+ lcd.printInt((unsigned int)value % 10000, 4);
+ break;
+ case PID_SPEED:
+ if (lastSpeed != value) {
+ lcd.setCursor(0, 0);
+ lcd.setFont(FONT_SIZE_XLARGE);
+ lcd.printInt((unsigned int)value % 1000, 3);
+ lastSpeed = value;
+ }
+ break;
+ case PID_THROTTLE:
+ lcd.setCursor(24, 5);
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.printInt(value % 100, 3);
+ break;
+ case PID_INTAKE_TEMP:
+ if (value < 1000) {
+ lcd.setCursor(102, 5);
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.printInt(value, 3);
+ }
+ break;
+ }
+ }
+ void showGForce(int g)
+ {
+ byte n;
+ /* 0~1.5g -> 0~8 */
+ g /= 85 * 25;
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(0, 3);
+ if (g == 0) {
+ lcd.clearLine(1);
+ } else if (g < 0 && g >= -10) {
+ for (n = 0; n < 10 + g; n++) {
+ lcd.write(' ');
+ }
+ for (; n < 10; n++) {
+ lcd.write('<');
+ }
+ lcd.print(" ");
+ } else if (g > 0 && g < 10) {
+ lcd.print(" ");
+ for (n = 0; n < g; n++) {
+ lcd.write('>');
+ }
+ for (; n < 10; n++) {
+ lcd.write(' ');
+ }
+ }
+ }
+ void initLoggerScreen()
+ {
+ lcd.clear();
+ lcd.backlight(true);
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(24, 3);
+ lcd.print("km/h");
+ lcd.setCursor(110, 3);
+ lcd.print("rpm");
+ lcd.setCursor(0, 5);
+ lcd.print("THR: %");
+ lcd.setCursor(80, 5);
+ lcd.print("AIR: C");
+ }
+ void showTimerResults()
+ {
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(56, 0);
+ lcd.print(" 0~60: --");
+ lcd.setCursor(56, 2);
+ lcd.print("0~100: --");
+ lcd.setCursor(56, 4);
+ lcd.print("0~200: --");
+ lcd.setCursor(56, 6);
+ lcd.print(" 400m: --");
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ char buf[8];
+ if (times[0]) {
+ sprintf(buf, "%2d.%1d", times[0] / 10, times[0] % 10);
+ Serial.println(times[0]);
+ lcd.setCursor(92, 0);
+ lcd.print(buf);
+ }
+ if (times[1]) {
+ sprintf(buf, "%2d.%1d", times[1] / 10, times[1] % 10);
+ Serial.println(buf);
+ lcd.setCursor(92, 2);
+ lcd.print(buf);
+ }
+ if (times[2]) {
+ sprintf(buf, "%2d.%1d", times[2] / 10, times[2] % 10);
+ Serial.println(buf);
+ lcd.setCursor(92, 4);
+ lcd.print(buf);
+ }
+ if (times[3]) {
+ sprintf(buf, "%2d.%1d", times[3] / 10, times[3] % 10);
+ Serial.println(buf);
+ lcd.setCursor(92, 6);
+ lcd.print(buf);
+ }
+ }
+ void initTimerScreen()
+ {
+ lcd.clear();
+ showTimerResults();
+ lcd.setFont(FONT_SIZE_SMALL);
+ lcd.setCursor(24, 7);
+ lcd.print("km/h");
+ }
+};
+
+static COBDLogger logger;
+
+void setup()
+{
+#ifdef DEBUG
+ DEBUG.begin(DEBUG_BAUDRATE);
+ DEBUG.println("OBD logger debug console");
+#endif
+
+ lcd.begin();
+ lcd.backlight(true);
+ lcd.setFont(FONT_SIZE_MEDIUM);
+ lcd.println("OBD Logger");
+ lcd.println("Initializing");
+
+ logger.begin();
+ logger.initSender();
+
+#ifdef GPSUART
+#ifdef GPS_OPEN_BAUDRATE
+ GPSUART.begin(GPS_OPEN_BAUDRATE);
+ delay(10);
+ GPSUART.println(PMTK_SET_BAUDRATE);
+ GPSUART.end();
+#endif
+ GPSUART.begin(GPS_BAUDRATE);
+ // switching to 10Hz mode, effective only for MTK3329
+ //GPSUART.println(PMTK_SET_NMEA_OUTPUT_ALLDATA);
+ GPSUART.println(PMTK_SET_NMEA_UPDATE_10HZ);
+#endif
+
+#ifdef MODE_SWITCH_PIN
+ pinMode(MODE_SWITCH_PIN, INPUT);
+#endif
+
+#if ENABLE_DATA_LOG
+ logger.checkSD();
+#else
+ lcd.clear();
+#endif
+ logger.setup();
+
+#ifdef MODE_SWITCH_PIN
+ if (digitalRead(MODE_SWITCH_PIN) == 0) {
+ delay(500);
+ if (digitalRead(MODE_SWITCH_PIN) == 0) {
+ mode = 1 - mode;
+ logger.initScreen();
+ while (digitalRead(MODE_SWITCH_PIN) == 0);
+ }
+ }
+#endif
+}
+
+void loop()
+{
+ logger.loop();
+}