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 };