├── .gitattributes ├── Arduino_Telematics_V1_Base.skp ├── Arduino_Telematics_V1_Lid.skp ├── BluetoothScan └── BluetoothScan.ino ├── DataPlanning.xls ├── README.md └── SimpleArduinoObd ├── FileIO.h ├── GpsHelper.h ├── ObdHelper.h ├── SimpleArduinoObd.ino └── Strings.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Arduino_Telematics_V1_Base.skp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheForeignMan/SimpleArduinoObd/d3a97610c9ebb781fb4044eb9a86f727bfaf4355/Arduino_Telematics_V1_Base.skp -------------------------------------------------------------------------------- /Arduino_Telematics_V1_Lid.skp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheForeignMan/SimpleArduinoObd/d3a97610c9ebb781fb4044eb9a86f727bfaf4355/Arduino_Telematics_V1_Lid.skp -------------------------------------------------------------------------------- /BluetoothScan/BluetoothScan.ino: -------------------------------------------------------------------------------- 1 | // Set module to master AT+ROLE=1 2 | // Set module to connect to any address AT+CMODE=0 3 | // Set module password to 1234 AT+PSWD=1234 4 | // FROM NOW ON, KEY PIN HIGH ALWAYS!! 5 | // Initialise the SPP lib AT+INIT 6 | // Set module to look for devices with access code AT+IAC=9E8B33 7 | // Set to look for the device type AT+CLASS=0 8 | // Set enquiry parameters AT+INQM=1,9,48 (2nd param determines length of list [stop after 9 devices found]) 9 | // Get list of nearby devices AT+INQ 10 | // Find name of devices AT+RNAME?1234,56,789ABC 11 | // Set module to connect to one address AT+CMODE=1 12 | // Bind module to slave address AT+BIND=1234,56,789ABC 13 | // Pair module with slave AT+PAIR=1234,56,789ABC,10 (10s timeout should be ok) 14 | // Check slave is in pair list AT+FSAD=1234,56,789ABC 15 | // Connect to slave AT+LINK=1234,56,789ABC 16 | // Disconnect once done AT+DISC 17 | 18 | #define BT_PWR 19 19 | #define BT_KEY 3 20 | #define SHOW_OUTPUT true 21 | 22 | bool nextCommandReady = false; 23 | 24 | char newLine[] = "\r\n"; 25 | 26 | String * availableDevices;//[9] = {"","","","","","","","",""}; 27 | 28 | void setup() 29 | { 30 | // put your setup code here, to run once: 31 | pinMode(BT_PWR, OUTPUT); 32 | digitalWrite(BT_PWR, LOW); 33 | pinMode(BT_KEY, OUTPUT); 34 | digitalWrite(BT_KEY, LOW); 35 | 36 | Serial.begin(115200); 37 | Serial2.begin(38400); 38 | delay(100); 39 | Bluetooth(HIGH); 40 | delay(1000); 41 | nextCommandReady = true; 42 | AutoConnect(); 43 | delay(1000); 44 | Serial.println("Enter OBD commands: "); 45 | nextCommandReady = true; 46 | delay(1000); 47 | } 48 | 49 | void Bluetooth(bool enable) 50 | { 51 | digitalWrite(BT_KEY, enable); 52 | delay(100); 53 | digitalWrite(BT_PWR, enable); 54 | delay(1000); 55 | if(enable) 56 | Serial.println("Bluetooth enabled"); 57 | else 58 | Serial.println("Bluetooth disabled"); 59 | } 60 | 61 | bool responseReceived = false; 62 | String command = ""; 63 | String response = ""; 64 | void loop() 65 | { 66 | // put your main code here, to run repeatedly: 67 | if(Serial.available() > 0) 68 | { 69 | while(Serial.available()) 70 | { 71 | char charByte = Serial.read(); 72 | command += charByte; 73 | if(command[command.length() - 2] == '\r' && command[command.length() - 1] == '\n') 74 | { 75 | SendToBluetooth(command, true); 76 | command = ""; 77 | } 78 | } 79 | } 80 | 81 | if(Serial2.available() > 0) 82 | { 83 | while(Serial2.available()) 84 | { 85 | char charByte = Serial2.read(); 86 | response += charByte; 87 | if(response[response.length() - 1] == '>') 88 | { 89 | //WriteToTerminal(response); 90 | responseReceived = true; 91 | } 92 | 93 | Serial.write(charByte); 94 | } 95 | } 96 | 97 | if(responseReceived) 98 | { 99 | nextCommandReady = true; 100 | 101 | // Determine the response from the OBD 102 | for(int i = 0; i < response.length(); i++) 103 | { 104 | //if(i == response.length()) 105 | } 106 | 107 | response = ""; 108 | } 109 | 110 | } 111 | 112 | 113 | void SendToBluetooth(String command, bool printCommand) 114 | { 115 | if(nextCommandReady) 116 | { 117 | response = ""; 118 | if(printCommand) 119 | { 120 | Serial.print(F("Command sent: ")); Serial.println(command); 121 | } 122 | for(int i = 0; i < command.length(); i++) 123 | { 124 | Serial2.write(command[i]); 125 | } 126 | Serial2.flush(); 127 | nextCommandReady = false; 128 | } 129 | else 130 | { 131 | Serial.print("Not ready!["); 132 | Serial.print(command); 133 | Serial.println("]"); 134 | } 135 | } 136 | 137 | void WriteToTerminal(String response) 138 | { 139 | Serial.println(response); 140 | response = ""; 141 | } 142 | 143 | String * StringSplit(String response) 144 | { 145 | // Count number of new lines/carriage returns 146 | int i = 0; 147 | int numberOfNewLines = 0; 148 | for (i = 0; i < response.length(); i++) 149 | { 150 | response[i] == '\r' ? numberOfNewLines++ : i++; 151 | } 152 | Serial.print("Number of new lines = "); Serial.println(i); 153 | 154 | String returnArray[numberOfNewLines]; 155 | 156 | bool carriageReturn = false; 157 | int newLine = 0; 158 | for(int j = 0; j < response.length(); j++) 159 | { 160 | if(response[j] == '\r') 161 | { 162 | carriageReturn = true; 163 | } 164 | else if(response[j] == '\n' && carriageReturn) 165 | { 166 | newLine++; 167 | } 168 | else 169 | { 170 | returnArray[newLine] += response[j]; 171 | } 172 | } 173 | 174 | return returnArray; 175 | } 176 | 177 | bool StringContains(String str, String subString) 178 | { 179 | return str.indexOf(subString) >= 0; 180 | } 181 | 182 | 183 | void AutoConnect() 184 | { 185 | // Check that the device is in AT mode 186 | SendToBluetooth(F("AT\r\n"), SHOW_OUTPUT); 187 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 188 | 189 | // Reset to original parameters 190 | SendToBluetooth(F("AT+ORGL\r\n"), SHOW_OUTPUT); 191 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 192 | 193 | // Reset the device 194 | SendToBluetooth(F("AT+RESET\r\n"), SHOW_OUTPUT); 195 | WaitForResponse(true, SHOW_OUTPUT); delay(1000); 196 | 197 | // Check that the device is in AT mode 198 | SendToBluetooth(F("AT\r\n"), SHOW_OUTPUT); 199 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 200 | 201 | // Set the UART properties of the module 202 | SendToBluetooth(F("AT+UART=115200,0,0\r\n"), SHOW_OUTPUT); 203 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 204 | 205 | // Set the role to MASTER 206 | SendToBluetooth(F("AT+ROLE=1\r\n"), SHOW_OUTPUT); 207 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 208 | 209 | // Set module to connect to any address (open channel) 210 | SendToBluetooth(F("AT+CMODE=0\r\n"), SHOW_OUTPUT); 211 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 212 | 213 | // Set module password to 1234 214 | SendToBluetooth(F("AT+PSWD=1234\r\n"), SHOW_OUTPUT); 215 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 216 | 217 | // From now on, the key pin MUST be held high! 218 | // Might already be high, but just in case... 219 | digitalWrite(BT_KEY, HIGH); delay(100); 220 | 221 | // Initialise the SPP library 222 | SendToBluetooth(F("AT+INIT\r\n"), SHOW_OUTPUT); 223 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 224 | 225 | // Set module to look for device with access code 9E8B33 226 | SendToBluetooth(F("AT+IAC=9E8B33\r\n"), SHOW_OUTPUT); 227 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 228 | 229 | // Set module to look for specific device type 230 | SendToBluetooth(F("AT+CLASS=0\r\n"), SHOW_OUTPUT); 231 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 232 | 233 | // Set enquiry parameters 234 | SendToBluetooth(F("AT+INQM=1,3,48\r\n"), SHOW_OUTPUT); 235 | WaitForResponse(true, SHOW_OUTPUT); delay(100); 236 | 237 | // Get a list of nearby devices matching the criteria above (IAC) 238 | SendToBluetooth(F("AT+INQ\r\n"), true); 239 | WaitForResponse(false, true); delay(1000); 240 | 241 | // For each device nearby, check their name 242 | // Returned string for each device: +INQ:2:72:D2224,3E0104,FFBC 243 | // in the form of +INQ:,, 244 | // EC88:92:98AF91 <= phone 245 | 246 | bool macAddressFlag = false; 247 | long macAddressLong = 0; 248 | char macAddress1[3][15] = {0}; 249 | byte addressCountRow = 0; 250 | byte addressCountCol = 0; 251 | for(int j = 4; j < response.length(); j++) 252 | { 253 | if(response[j] == ':' && 254 | response[j-1] == 'Q' && 255 | response[j-2] == 'N' && 256 | response[j-3] == 'I' && 257 | response[j-4] == '+') 258 | { 259 | macAddressFlag = true; 260 | } 261 | else if(macAddressFlag) 262 | { 263 | if(response[j] == ',') 264 | { 265 | macAddressFlag = false; 266 | macAddress1[addressCountRow][addressCountCol] = 0; 267 | addressCountRow++; 268 | addressCountCol = 0; 269 | //Serial.println(); 270 | } 271 | else if(response[j] == ':') 272 | { 273 | macAddress1[addressCountRow][addressCountCol] = ','; 274 | //Serial.print(macAddress1[addressCountRow][addressCountCol]); 275 | addressCountCol++; 276 | } 277 | else 278 | { 279 | macAddress1[addressCountRow][addressCountCol] = response[j]; 280 | //Serial.print(macAddress1[addressCountRow][addressCountCol]); 281 | addressCountCol++; 282 | } 283 | } 284 | } 285 | 286 | if (addressCountRow == 0) 287 | { 288 | Serial.println("No Bluetooth devices found. Check there are devices available, and restart the Arduino."); 289 | while(1); 290 | } 291 | 292 | for(int i = 0; i < 3; i++) 293 | { 294 | // Now that the MAC address has been obtained, a name query can be made. 295 | Serial.println(); 296 | // Serial.print("MAC Address: "); Serial.println(macAddress1[i]); 297 | 298 | // Now that the MAC address has been obtained, a name query can be made. 299 | // For some reason, the size of the array row must be displayed, otherwise 300 | // the name-query will fail. No idea why. 301 | /*Serial.print("Size of array: "); */Serial.print(sizeof(macAddress1[i])); 302 | //Serial.print(" Device "); delay(1000); Serial.print(i+1); delay(1000); Serial.println(" :"); 303 | //Serial.flush(); 304 | delay(1000); 305 | char commandName[] = "AT+RNAME?"; 306 | strcat(commandName, macAddress1[i]); 307 | 308 | SendToBluetooth(strcat(commandName, newLine), true); 309 | WaitForResponse(true,true); delay(100); 310 | } 311 | 312 | response = ""; 313 | char inputChar = 0; 314 | while (inputChar != '1' && inputChar != '2' && inputChar != '3') 315 | { 316 | Serial.println(); 317 | Serial.print("Select the device to connect to: "); 318 | while(Serial.available() == 0); 319 | inputChar = Serial.read(); 320 | while(Serial.available() != 0) Serial.read(); 321 | Serial.println(inputChar); 322 | } 323 | 324 | digitalWrite(BT_KEY, HIGH); 325 | 326 | Serial.print("Device selected: "); Serial.println(macAddress1[inputChar-49]); 327 | 328 | Bluetooth(LOW); 329 | delay(1000); 330 | Serial2.end(); 331 | delay(500); 332 | Serial2.begin(38400); 333 | delay(500); 334 | Bluetooth(HIGH); 335 | delay(1000); 336 | 337 | // Check that the device is in AT mode 338 | SendToBluetooth(F("AT\r\n"), SHOW_OUTPUT); 339 | WaitForResponse(true, SHOW_OUTPUT); 340 | Serial.println(F("Received from AT"));delay(1000); 341 | 342 | // Initialise the SPP library 343 | SendToBluetooth(F("AT+INIT\r\n"), SHOW_OUTPUT); 344 | WaitForResponse(true, SHOW_OUTPUT); delay(1000); 345 | 346 | // Set to 1 347 | SendToBluetooth(F("AT+CMODE=1\r\n"), SHOW_OUTPUT); 348 | WaitForResponse(true, SHOW_OUTPUT); delay(1000); 349 | 350 | char cmdFull[30] = {0}; 351 | 352 | // Bind to one address 353 | char cmd0[] = "AT+BIND="; 354 | strcat(cmdFull, cmd0); 355 | strcat(cmdFull, macAddress1[inputChar-49]); 356 | SendToBluetooth(strcat(cmdFull, newLine), SHOW_OUTPUT); 357 | WaitForResponse(true, SHOW_OUTPUT); delay(1000); 358 | 359 | // Pair with it 360 | memset(cmdFull, 0, sizeof(cmdFull)); 361 | char timeout[] = ",10"; 362 | char cmd1[] = "AT+PAIR="; 363 | strcat(cmdFull, cmd1); 364 | strcat(cmdFull, macAddress1[inputChar-49]); 365 | strcat(cmdFull, timeout); 366 | SendToBluetooth(strcat(cmdFull, newLine), SHOW_OUTPUT); 367 | WaitForResponse(true, SHOW_OUTPUT); delay(1000); 368 | 369 | // Check it is in the paring list 370 | memset(cmdFull, 0, sizeof(cmdFull)); 371 | char cmd2[] = "AT+FSAD="; 372 | strcat(cmdFull, cmd2); 373 | strcat(cmdFull, macAddress1[inputChar-49]); 374 | SendToBluetooth(strcat(cmdFull, newLine), SHOW_OUTPUT); 375 | WaitForResponse(true, SHOW_OUTPUT); delay(1000); 376 | 377 | // Connect to it. 378 | memset(cmdFull, 0, sizeof(cmdFull)); 379 | char cmd3[] = "AT+LINK="; 380 | strcat(cmdFull, cmd3); 381 | strcat(cmdFull, macAddress1[inputChar-49]); 382 | SendToBluetooth(strcat(cmdFull, newLine), SHOW_OUTPUT); 383 | WaitForResponse(true, SHOW_OUTPUT); delay(1000); 384 | } 385 | 386 | void CheckReceiverBuffer(bool showResponse) 387 | { 388 | if(Serial2.available() > 0) 389 | { 390 | while(Serial2.available()) 391 | { 392 | char charByte = Serial2.read(); 393 | response += charByte; 394 | if(response[response.length() - 2] == '\r' && response[response.length() - 1] == '\n') 395 | { 396 | //WriteToTerminal(response); 397 | responseReceived = true; 398 | } 399 | //Serial.print("Char received: "); 400 | if(showResponse) 401 | Serial.write(charByte); 402 | //Serial.println(); 403 | } 404 | } 405 | } 406 | 407 | void WaitForResponse(bool clearResponse) 408 | { 409 | WaitForResponse(clearResponse, false); 410 | } 411 | 412 | void WaitForResponse(bool clearResponse, bool showResponse) 413 | { 414 | while(!(responseReceived && 415 | (StringContains(response, F("OK")) || 416 | StringContains(response, F("ERROR")) || 417 | StringContains(response, F("FAIL"))))) 418 | { 419 | //delay(1000); 420 | CheckReceiverBuffer(showResponse); 421 | } 422 | 423 | if(clearResponse) response = ""; 424 | 425 | nextCommandReady = true; 426 | } 427 | 428 | 429 | -------------------------------------------------------------------------------- /DataPlanning.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheForeignMan/SimpleArduinoObd/d3a97610c9ebb781fb4044eb9a86f727bfaf4355/DataPlanning.xls -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleArduinoObd 2 | 3 | Plan: 4 | - [DONE] Connect to ELM327 Bluetooth OBD adapter with Arduino and HC-05. 5 | - [DONE] Request data from OBD connector, and print to terminal. 6 | - [DONE] Save data to SD card for every trip. 7 | - [DONE] Get GPS coordinates to determine location, and determine time. 8 | - [DONE] Save GPS and time to file, naming file according to time. 9 | -------------------------------------------------------------------------------- /SimpleArduinoObd/FileIO.h: -------------------------------------------------------------------------------- 1 | 2 | File myFile; 3 | File root; 4 | char fileName[30] = {0}; 5 | const char entryFormat[] = "%02d/%02d/%02d,%02d:%02d:%02d,%s,%s,%05d,%04d,%04d"; // 55+ bytes 6 | char entryArray[80] = {0}; 7 | char rootLocation[] = "/"; 8 | static bool isRootOpened = false; 9 | Sd2Card card; 10 | SdVolume volume; 11 | SdFile root2; 12 | 13 | 14 | //////////////////////// 15 | // FUNCTION DECLARATIONS 16 | //////////////////////// 17 | void InitialiseSdCard(int chipSelect); 18 | void SetFileName(byte year, byte month, byte day, byte hour); 19 | bool WriteToFile(char* text, int textLength); 20 | void ShowCardInfo(); 21 | uint32_t GetVolumeSize(Sd2Card sdCard, SdVolume vol); 22 | void PrintCardContents(); 23 | uint32_t GetSizeOfAllFiles(); 24 | uint32_t GetSizeOfAllFiles(File dir); 25 | void printDirectory(File dir, int numTabs); 26 | 27 | 28 | /////////////////////// 29 | // FUNCTION DEFINITIONS 30 | /////////////////////// 31 | 32 | // Initialises the SD card to prepare for writing to files, 33 | // and reading card information. 34 | void InitialiseSdCard(int chipSelect) 35 | { 36 | if(!SD.begin(chipSelect)) 37 | { 38 | #if DEBUG 39 | Serial.print(F("SD initialisation failed.")); 40 | #endif 41 | while(1); 42 | } 43 | 44 | // we'll use the initialization code from the utility libraries 45 | // since we're just testing if the card is working! 46 | if (!card.init(SPI_HALF_SPEED, chipSelect)) 47 | { 48 | #if DEBUG 49 | Serial.println("initialization failed. Things to check:"); 50 | Serial.println("* is a card inserted?"); 51 | Serial.println("* is your wiring correct?"); 52 | Serial.println("* did you change the chipSelect pin to match your shield or module?"); 53 | #endif 54 | while (1); 55 | } 56 | else 57 | { 58 | #if DEBUG 59 | Serial.println("Wiring is correct and a card is present."); 60 | #endif 61 | } 62 | } 63 | 64 | 65 | // Sets the file name for the text file. 66 | // - year - byte with the year number 67 | // - month - byte with the month number 68 | // - day - byte with the day number 69 | // - hour - byte with the hour number 70 | void SetFileName(byte year, byte month, byte day, byte hour, byte minute) 71 | { 72 | sprintf(fileName, 73 | "%02d%02d%02d%02d", 74 | // "%02d%02d%02d%02d%02d", // Setting the minutes in the filename seems to fail creating a file for some reason... 75 | year, month, day, hour, minute); 76 | 77 | #if DEBUG 78 | Serial.print(F("File name: ")); 79 | Serial.println(fileName); 80 | #endif 81 | } 82 | 83 | 84 | // Writes text to file. 85 | // - text - char array containing the text to write 86 | // - textLength - the length of array 87 | bool WriteToFile(char* text, int textLength) 88 | { 89 | myFile = SD.open(fileName, O_RDWR | O_CREAT | O_APPEND); 90 | if(myFile) 91 | { 92 | for(int i = 0; i < textLength; i++) 93 | { 94 | char c = *(text+i); 95 | if(c == 0 || c == '\0') 96 | break; 97 | myFile.write(*(text+i)); 98 | } 99 | myFile.println(); 100 | myFile.close(); 101 | return true; 102 | } 103 | return false; 104 | } 105 | 106 | 107 | // Shows card info, such as card type and volume size, on the terminal. 108 | // Only prints if the program is compiled in DEBUG mode. 109 | void ShowCardInfo() 110 | { 111 | #if DEBUG 112 | // print the type of card 113 | Serial.println(); 114 | Serial.print("Card type: "); 115 | switch (card.type()) 116 | { 117 | case SD_CARD_TYPE_SD1: 118 | Serial.println("SD1"); 119 | break; 120 | case SD_CARD_TYPE_SD2: 121 | Serial.println("SD2"); 122 | break; 123 | case SD_CARD_TYPE_SDHC: 124 | Serial.println("SDHC"); 125 | break; 126 | default: 127 | Serial.println("Unknown"); 128 | } 129 | 130 | // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 131 | if (!volume.init(card)) 132 | { 133 | Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); 134 | while (1); 135 | } 136 | 137 | Serial.print("Clusters: "); 138 | Serial.println(volume.clusterCount()); 139 | Serial.print("Blocks x Cluster: "); 140 | Serial.println(volume.blocksPerCluster()); 141 | 142 | Serial.print("Total Blocks: "); 143 | Serial.println(volume.blocksPerCluster() * volume.clusterCount()); 144 | Serial.println(); 145 | 146 | // print the type and size of the first FAT-type volume 147 | uint32_t volumesize; 148 | Serial.print("Volume type is: FAT"); 149 | Serial.println(volume.fatType(), DEC); 150 | 151 | volumesize = volume.blocksPerCluster(); // clusters are collections of blocks 152 | volumesize *= volume.clusterCount(); // we'll have a lot of clusters 153 | volumesize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB) 154 | Serial.print("Volume size (Kb): "); 155 | Serial.println(volumesize); 156 | Serial.print("Volume size (Mb): "); 157 | volumesize /= 1024; 158 | Serial.println(volumesize); 159 | Serial.print("Volume size (Gb): "); 160 | Serial.println((float)volumesize / 1024.0); 161 | #endif 162 | } 163 | 164 | 165 | // Gets the volume size of the SD card in KB, as this is more detailed than in 166 | // MB or GB. 167 | // - sdCard - the location of the SD card 168 | // - vol - the location of the volume of said SD card 169 | uint32_t GetVolumeSizeInKb(Sd2Card sdCard, SdVolume vol) 170 | { 171 | // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 172 | if (!vol.init(sdCard)) 173 | { 174 | #if DEBUG 175 | Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); 176 | #endif 177 | while (1); 178 | } 179 | uint32_t volumeSize = vol.blocksPerCluster(); // clusters are collections of blocks 180 | volumeSize *= vol.clusterCount(); // we'll have a lot of clusters 181 | volumeSize /= 2; // SD card blocks are always 512 bytes (2 blocks are 1KB) 182 | 183 | return volumeSize; 184 | } 185 | 186 | 187 | // Print the contents of the SD card, including files/folders, date modified, 188 | // and file size (KB). To be used in DEBUG mode only. 189 | void PrintCardContents() 190 | { 191 | #if DEBUG 192 | if (!volume.init(card)) 193 | { 194 | Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); 195 | while (1); 196 | } 197 | Serial.println("\nFiles found on the card (name, date and size in bytes): "); 198 | root2.openRoot(volume); 199 | 200 | // list all files in the card with date and size 201 | root2.ls(LS_R | LS_DATE | LS_SIZE); 202 | 203 | root2.close(); 204 | Serial.println(); 205 | #endif 206 | } 207 | 208 | 209 | // Gets the total size of all files on the card. This will show how much 210 | // space is used up by the files from the root directory. 211 | uint32_t GetSizeOfAllFiles() 212 | { 213 | if(isRootOpened) 214 | { 215 | root.rewindDirectory(); 216 | } 217 | else 218 | { 219 | root = SD.open(rootLocation, FILE_READ); 220 | isRootOpened = true; 221 | } 222 | return GetSizeOfAllFiles(root); 223 | } 224 | 225 | 226 | // Gets the total size of all files in the folder 'dir'. This will show how much 227 | // space is used up by the files from this directory. 228 | // - dir - the folder location to get file details from. 229 | uint32_t GetSizeOfAllFiles(File dir) 230 | { 231 | uint32_t sizeOfAllFiles = 0; 232 | while (true) 233 | { 234 | File entry = dir.openNextFile(); 235 | if (! entry) 236 | { 237 | // no more files 238 | entry.close(); 239 | dir.rewindDirectory(); 240 | return sizeOfAllFiles; 241 | } 242 | 243 | if (entry.isDirectory()) 244 | { 245 | sizeOfAllFiles += GetSizeOfAllFiles(entry); 246 | } 247 | else 248 | { 249 | // files have sizes, directories do not 250 | sizeOfAllFiles += entry.size(); 251 | } 252 | entry.close(); 253 | } 254 | } 255 | 256 | 257 | // Another way of printing the contents of the SD card, but does not 258 | // print dates. To be used in DEBUG mode only. 259 | // - dir - directory from which to print files 260 | // - numTabs - number of tab characters ('\t') to start off from 261 | void printDirectory(File dir, int numTabs) 262 | { 263 | while (true) 264 | { 265 | File entry = dir.openNextFile(); 266 | if (! entry) 267 | { 268 | // no more files 269 | dir.rewindDirectory(); 270 | break; 271 | } 272 | 273 | for (uint8_t i = 0; i < numTabs; i++) 274 | Serial.print('\t'); 275 | 276 | Serial.print(entry.name()); 277 | if (entry.isDirectory()) 278 | { 279 | Serial.println("/"); 280 | printDirectory(entry, numTabs + 1); 281 | } 282 | else 283 | { 284 | // files have sizes, directories do not 285 | Serial.print("\t\t"); 286 | Serial.println(entry.size(), DEC); 287 | } 288 | entry.close(); 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /SimpleArduinoObd/GpsHelper.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // GPS variables 4 | TinyGPS gps; 5 | bool newData = false; 6 | struct GpsData 7 | { 8 | float lat; 9 | float lon; 10 | uint32_t timeRaw; 11 | byte second; 12 | byte minute; 13 | byte hour; 14 | uint32_t dateRaw; 15 | byte day; 16 | byte month; 17 | byte year; 18 | }; 19 | 20 | GpsData currentGpsData; 21 | 22 | 23 | //////////////////////// 24 | // FUNCTION DECLARATIONS 25 | //////////////////////// 26 | void InitialiseGps(); 27 | bool IsGpsDataAvailable(bool showOutput); 28 | void GetGpsData(GpsData* dest); 29 | 30 | 31 | /////////////////////// 32 | // FUNCTION DEFINITIONS 33 | /////////////////////// 34 | 35 | // Initialises the GPS module. 36 | void InitialiseGps() 37 | { 38 | Serial3.begin(9600); 39 | memset(¤tGpsData, 0, sizeof(GpsData)); 40 | } 41 | 42 | 43 | // Waits until there is valid GPS data before returning true for yes. 44 | bool IsGpsDataAvailable(bool showOutput) 45 | { 46 | // For one second we parse GPS data and report some key values 47 | for (unsigned long start = millis(); millis() - start < 1000;) 48 | { 49 | while (Serial3.available()) 50 | { 51 | char c = Serial3.read(); 52 | if (showOutput) 53 | { 54 | Serial.write(c); // uncomment this line if you want to see the GPS data flowing 55 | } 56 | 57 | if(gps.encode(c)) 58 | { 59 | return true; 60 | } 61 | } 62 | } 63 | return false; 64 | } 65 | 66 | 67 | // Gets the GPS data, only if valid. 68 | void GetGpsData(GpsData* dest) 69 | { 70 | float flat, flon; 71 | unsigned long age1; 72 | gps.f_get_position(&flat, &flon, &age1); 73 | unsigned long date, time, age2; 74 | gps.get_datetime(&date, &time, &age2); 75 | 76 | // Set new coordinates - Latitude 77 | if(flat != TinyGPS::GPS_INVALID_F_ANGLE) 78 | dest->lat = flat; 79 | 80 | // Set new coordinates - Longitude 81 | if(flon != TinyGPS::GPS_INVALID_F_ANGLE) 82 | dest->lon = flon; 83 | 84 | // Set the date 85 | if(date != TinyGPS::GPS_INVALID_DATE) 86 | { 87 | dest->dateRaw = date; 88 | // returned date is in format DDMMYY 89 | dest->year = date %100; 90 | dest->month = (date / 100) % 100; 91 | dest->day = date / 10000; 92 | } 93 | 94 | // Set the time 95 | if(time != TinyGPS::GPS_INVALID_TIME) 96 | { 97 | dest->timeRaw = time; 98 | // returned time is in format HHMMSScc (what's cc?) 99 | dest->hour = time / 1000000; 100 | dest->minute = (time / 10000) % 100; 101 | dest->second = (time / 100) % 100; 102 | } 103 | } 104 | 105 | -------------------------------------------------------------------------------- /SimpleArduinoObd/ObdHelper.h: -------------------------------------------------------------------------------- 1 | // HEADERS 2 | //////////////////////// 3 | #include "Strings.h" 4 | 5 | // DEFINES 6 | //////////////////////// 7 | #define BT_PWR 19 8 | #define BT_GND 18 9 | #define BT_KEY 3 10 | //#define BT_RX 4 11 | //#define BT_TX 3 12 | 13 | #define MODE_01 0x0100 14 | //#define PIDS_AVAIL 0x00 15 | #define ENGINE_RPM 0x0C 16 | #define VEHICLE_SPEED 0x0D 17 | #define ACCEL_POS 0x11 18 | 19 | #define SHOW_OUTPUT false 20 | 21 | // Change this according to your vehicle! 22 | #define RESPONSE_PREFIX_OFFSET 4 23 | 24 | // GLOBAL VARIABLES 25 | //////////////////////// 26 | 27 | struct ObdHolder 28 | { 29 | uint16_t RPM; // 2 bytes 30 | uint8_t Speed; // 1 byte 31 | uint8_t Throttle; // 1 byte 32 | } currentObdReading; // Total size of struct = 4 bytes 33 | 34 | // CHANGE THIS MAC ADDRESS TO OBDII BT MAC ADDRESS 35 | const char obdMacAddress[] = "1D,A5,68988B"; 36 | const char cmdCheck[] = "AT"; 37 | const char cmdInit[] = "+INIT"; 38 | const char cmdPair[] = "+PAIR="; 39 | const char cmdPairTimeout[] = ",10"; 40 | const char cmdPairCheck[] = "+FSAD="; 41 | const char cmdConnect[] = "+LINK="; 42 | const char cmdPids[] = "0100"; 43 | const char cmdRpm[] = "010C"; 44 | const char cmdSpeed[] = "010D"; 45 | const char cmdThrottle[] = "0111"; 46 | const char newLine[] = "\r\n"; 47 | const char btResponseOk[] = "OK"; 48 | const char btResponseError[] = "ERROR"; 49 | const char btResponseFail[] = "FAIL"; 50 | const char obdNoData[] = "NO DATA"; 51 | 52 | const byte arraySize = 30; 53 | char cmdFull[arraySize] = {0}; 54 | char command[arraySize] = {0}; byte cmdIndex = 0; 55 | char response[arraySize] = {0}; byte responseIndex = 0; 56 | char mainResponse[arraySize] = {0}; byte mainResponseIndex = 0; 57 | 58 | byte numberOfCmdsReceived = 0; 59 | byte receivedCommands[8] = {0}; 60 | 61 | byte value = 0; 62 | byte addition = 0; 63 | byte* pValue = &value; 64 | byte* pAddition = &addition; 65 | 66 | uint16_t* pRpm = &(currentObdReading.RPM); 67 | uint8_t* pSpeed = &(currentObdReading.Speed); 68 | uint8_t* pThrottle = &(currentObdReading.Throttle); 69 | 70 | bool startByteReceived = false; 71 | bool pidByteReceived = false; 72 | byte pidReceived = 0; 73 | uint32_t responseData = 0; 74 | 75 | int commandCount = 0; 76 | 77 | bool nextCommandReady = false; 78 | bool responseReceived = false; 79 | 80 | // FUNCTION DECLARATIONS 81 | //////////////////////// 82 | 83 | bool InitBluetoothComms(); 84 | bool ConnectToObdDevice(); 85 | void Bluetooth(bool enable); 86 | void GetObdReadings(const ObdHolder* holder); 87 | void SendToBluetooth(const char *pCommand, const int commandLength, bool printCommand); 88 | void CheckReceiverBuffer(bool showResponse); 89 | bool WaitForResponse(bool clearResponse); 90 | bool WaitForResponse(bool clearResponse, bool showResponse); 91 | 92 | // FUNCTION DEFINITIONS 93 | //////////////////////// 94 | 95 | bool InitBluetoothComms() 96 | { 97 | pinMode(BT_GND, OUTPUT); 98 | digitalWrite(BT_GND, LOW); 99 | pinMode(BT_PWR, OUTPUT); 100 | digitalWrite(BT_PWR, LOW); 101 | pinMode(BT_KEY, OUTPUT); 102 | digitalWrite(BT_KEY, LOW); 103 | 104 | Serial2.begin(38400); 105 | while(!Serial2); 106 | Bluetooth(HIGH); 107 | nextCommandReady = true; 108 | 109 | while(Serial2.available() > 0) 110 | { 111 | Serial2.read(); 112 | } 113 | 114 | currentObdReading.RPM = -1; 115 | currentObdReading.Speed = -1; 116 | currentObdReading.Throttle = -1; 117 | 118 | return ConnectToObdDevice(); 119 | } 120 | 121 | bool ConnectToObdDevice() 122 | { 123 | bool deviceResponseOk = false; 124 | 125 | // Check that the device is in AT mode 126 | memset(cmdFull, 0, sizeof(cmdFull)); 127 | strcat(cmdFull, cmdCheck); 128 | strcat(cmdFull, newLine); 129 | SendToBluetooth(cmdFull, sizeof(cmdCheck) + sizeof(newLine) - 2, SHOW_OUTPUT); 130 | deviceResponseOk = WaitForResponse(true, SHOW_OUTPUT); 131 | 132 | if(!deviceResponseOk) 133 | { 134 | // Serial.println(F("Failed to talk to BT module")); 135 | Serial.println(-1); 136 | return false; 137 | } 138 | 139 | delay(100); 140 | 141 | // Initialise the SPP library 142 | memset(cmdFull, 0, sizeof(cmdFull)); 143 | strcat(cmdFull, cmdCheck); 144 | strcat(cmdFull, cmdInit); 145 | strcat(cmdFull, newLine); 146 | SendToBluetooth(cmdFull, sizeof(cmdCheck) + sizeof(cmdInit) + sizeof(newLine) - 3, SHOW_OUTPUT); 147 | deviceResponseOk = WaitForResponse(true, SHOW_OUTPUT); 148 | 149 | if(!deviceResponseOk) 150 | { 151 | // Serial.println(F("Failed to initialise BT module")); 152 | Serial.println(-2); 153 | return false; 154 | } 155 | 156 | delay(100); 157 | 158 | // Pair with it 159 | memset(cmdFull, 0, sizeof(cmdFull)); 160 | strcat(cmdFull, cmdCheck); 161 | strcat(cmdFull, cmdPair); 162 | strcat(cmdFull, obdMacAddress); 163 | strcat(cmdFull, cmdPairTimeout); 164 | strcat(cmdFull, newLine); 165 | SendToBluetooth(cmdFull, sizeof(cmdCheck) + sizeof(cmdPair) + sizeof(obdMacAddress) + sizeof(cmdPairTimeout) + sizeof(newLine) - 5, SHOW_OUTPUT); 166 | //WaitForResponse(true, SHOW_OUTPUT); delay(1000) 167 | deviceResponseOk = WaitForResponse(true, SHOW_OUTPUT); 168 | 169 | if(!deviceResponseOk) 170 | { 171 | // Serial.println(F("Failed to pair with OBD device")); 172 | Serial.println(-3); 173 | return false; 174 | } 175 | 176 | delay(100); 177 | 178 | // Check it is in the paring list 179 | memset(cmdFull, 0, sizeof(cmdFull)); 180 | strcat(cmdFull, cmdCheck); 181 | strcat(cmdFull, cmdPairCheck); 182 | strcat(cmdFull, obdMacAddress); 183 | strcat(cmdFull, newLine); 184 | SendToBluetooth(cmdFull, sizeof(cmdCheck) + sizeof(cmdPairCheck) + sizeof(obdMacAddress) + sizeof(newLine) - 4, SHOW_OUTPUT); 185 | deviceResponseOk = WaitForResponse(true, SHOW_OUTPUT); 186 | 187 | if(!deviceResponseOk) 188 | { 189 | // Serial.println(F("MAC address not in pairing list")); 190 | Serial.println(-4); 191 | return false; 192 | } 193 | 194 | delay(100); 195 | 196 | // Connect to it. 197 | memset(cmdFull, 0, sizeof(cmdFull)); 198 | strcat(cmdFull, cmdCheck); 199 | strcat(cmdFull, cmdConnect); 200 | strcat(cmdFull, obdMacAddress); 201 | strcat(cmdFull, newLine); 202 | SendToBluetooth(cmdFull, sizeof(cmdCheck) + sizeof(cmdConnect) + sizeof(obdMacAddress) + sizeof(newLine) - 4, SHOW_OUTPUT); 203 | deviceResponseOk = WaitForResponse(true, SHOW_OUTPUT); 204 | 205 | if(!deviceResponseOk) 206 | { 207 | // Serial.println(F("Failed to connect to device")); 208 | Serial.println(-5); 209 | return false; 210 | } 211 | 212 | return deviceResponseOk; 213 | } 214 | 215 | 216 | void Bluetooth(bool enable) 217 | { 218 | digitalWrite(BT_KEY, enable); 219 | delay(100); 220 | digitalWrite(BT_PWR, enable); 221 | #if SHOW_OUTPUT 222 | Serial.print(F("Bluetooth ")); 223 | if(enable) 224 | Serial.println(F("enabled")); 225 | else 226 | Serial.println(F("disabled")); 227 | #endif 228 | delay(1000); 229 | } 230 | 231 | 232 | void GetObdReadings(const ObdHolder* holder) 233 | { 234 | // We are only sending 3 commands - speed, RPM, throttle 235 | while(commandCount < 3) 236 | { 237 | // We're not interested in what's coming from the main UART bus, so no need to check that 238 | // We will check for any responses before sending anything over. 239 | if(Serial2.available() > 0) 240 | { 241 | while(Serial2.available()) 242 | { 243 | response[responseIndex] = Serial2.read(); 244 | //Serial.print(response[responseIndex]); // sends received response to uart 245 | // '>' marks end of response of OBD 246 | if(response[responseIndex] == '>') 247 | { 248 | responseReceived = true; 249 | } 250 | responseIndex++; 251 | if(responseIndex >= arraySize) 252 | { 253 | responseIndex = arraySize - 1; 254 | } 255 | } 256 | } 257 | 258 | // Determine the response from the OBDII device when the full message has been received 259 | if(responseReceived) 260 | { 261 | nextCommandReady = true; 262 | 263 | // Check if the data return is valid. A response of "NO DATA" means that there is no data 264 | // and the car cannot provide the value requested. Ergo, don't check for values, and move on. 265 | if(StringContains(response, obdNoData)) 266 | { 267 | responseReceived = false; 268 | memset(response, 0, arraySize); 269 | responseIndex = 0; 270 | continue; 271 | } 272 | 273 | // Each response we get is comprised of a series of 3 bytes: 274 | // 1. upper nibble 275 | // 2. lower nibble 276 | // 3. space character OR command terminator ('>') 277 | // Ergo, the number of command bytes received is the response index 278 | // divided by 3. 279 | 280 | // Ford Fiesta echos the command send, and immediately follows with the 281 | // response. Remove the first 4 bytes of echoed command bytes. 282 | numberOfCmdsReceived = (responseIndex - RESPONSE_PREFIX_OFFSET) / 3; 283 | memset(receivedCommands, 0, sizeof(receivedCommands)); 284 | int commandIndex = 0; 285 | *pValue = 0; 286 | *pAddition = 0; 287 | // Convert the response from the OBD to actual numbers (instead of a char array) 288 | for(int i = RESPONSE_PREFIX_OFFSET; i < responseIndex; i++) 289 | { 290 | // Only get the numbers if they are part of a hex digit. If it is not a hex digit, 291 | // the command has been completed, so move on to the next character. 292 | if(IsCharHexDigit(response[i])) 293 | { 294 | *pValue = receivedCommands[commandIndex]; // first time round, this is 0. Second is upper nibble. 295 | *pAddition = response[i]; 296 | if(response[i] >= '0' && response[i] <= '9') 297 | *pAddition -= 48; 298 | else if(response[i] >= 'A' && response[i] <= 'F') 299 | *pAddition -= 55; 300 | 301 | receivedCommands[commandIndex] = (*pValue << 4) + *pAddition; 302 | } 303 | else 304 | { 305 | commandIndex++; 306 | *pValue = 0; 307 | *pAddition = 0; 308 | } 309 | } 310 | 311 | responseReceived = false; 312 | 313 | // The response is no longer necessary, so can be emptied. 314 | memset(response, 0, sizeof(response)); 315 | responseIndex = 0; 316 | 317 | // Get the value from the response 318 | 319 | // Example command: 01 00 320 | // Example response: 41 00 BE 1F B8 10 321 | // 41 - Reponse for mode 01 (0x40 + 0x01) 322 | // 00 - Repeat of the PID number requested 323 | // Rest - data bytes 324 | 325 | // Example command: 01 0C [request RPM] 326 | // Example response: 41 0C 1A F8 327 | // 41 - Response for mode 01 328 | // 0C - Response for RPM 329 | // 1A F8 - value 6904. Actual RPM: 6904 / 4 = 1726 330 | 331 | startByteReceived = false; 332 | pidByteReceived = false; 333 | pidReceived = 0; 334 | responseData = 0; 335 | for(int i = 1; i < numberOfCmdsReceived; i++) 336 | { 337 | if(receivedCommands[i] == 0x41 && !startByteReceived) 338 | { 339 | startByteReceived = true; 340 | pidByteReceived = false; 341 | } 342 | else if(startByteReceived && !pidByteReceived) 343 | { 344 | pidReceived = receivedCommands[i]; 345 | switch(pidReceived) 346 | { 347 | // case PIDS_AVAIL: // 4 bytes return 348 | // responseData = (responseData << 8) + receivedCommands[++i]; 349 | // responseData = (responseData << 8) + receivedCommands[++i]; 350 | case ENGINE_RPM: // 2 bytes return 351 | responseData = (responseData << 8) + receivedCommands[++i]; 352 | case VEHICLE_SPEED: // 1 byte return 353 | case ACCEL_POS: // 1 byte return 354 | responseData = (responseData << 8) + receivedCommands[++i]; 355 | break; 356 | default: 357 | responseData = -1; 358 | break; 359 | } 360 | 361 | switch(pidReceived) 362 | { 363 | // case PIDS_AVAIL: 364 | // *pPid = responseData; 365 | // break; 366 | case ENGINE_RPM: 367 | *pRpm = ((uint16_t)responseData) / 4; 368 | break; 369 | case VEHICLE_SPEED: 370 | *pSpeed = (uint8_t)responseData; 371 | break; 372 | case ACCEL_POS: 373 | *pThrottle = (uint8_t)responseData; 374 | break; 375 | default: 376 | break; 377 | } 378 | 379 | startByteReceived = false; 380 | pidByteReceived = false; 381 | } 382 | } 383 | } 384 | 385 | // Send the next command if the device is ready 386 | if(nextCommandReady) 387 | { 388 | switch(commandCount) 389 | { 390 | case 0: 391 | memset(cmdFull, 0, sizeof(cmdFull)); 392 | strcat(cmdFull, cmdRpm); 393 | strcat(cmdFull, newLine); 394 | SendToBluetooth(cmdFull, sizeof(cmdRpm) + sizeof(newLine) - 2, SHOW_OUTPUT); 395 | break; 396 | case 1: 397 | memset(cmdFull, 0, sizeof(cmdFull)); 398 | strcat(cmdFull, cmdSpeed); 399 | strcat(cmdFull, newLine); 400 | SendToBluetooth(cmdFull, sizeof(cmdSpeed) + sizeof(newLine) - 2, SHOW_OUTPUT); 401 | break; 402 | case 2: 403 | memset(cmdFull, 0, sizeof(cmdFull)); 404 | strcat(cmdFull, cmdThrottle); 405 | strcat(cmdFull, newLine); 406 | SendToBluetooth(cmdFull, sizeof(cmdThrottle) + sizeof(newLine) - 2, SHOW_OUTPUT); 407 | break; 408 | } 409 | commandCount++; 410 | } 411 | } 412 | commandCount = 0; 413 | } 414 | 415 | void SendToBluetooth(const char *pCommand, const int commandLength, bool printCommand) 416 | { 417 | if(nextCommandReady || true) 418 | { 419 | memset(response, 0, sizeof(response)); 420 | responseIndex = 0; 421 | if(printCommand) 422 | { 423 | Serial.print(F("=>")); 424 | for(int i = 0; i < commandLength; i++) 425 | { 426 | if((*(pCommand + i)) != '\r' || (*(pCommand + i)) != '\n') 427 | Serial.write(*(pCommand + i)); 428 | // Serial.print(*(pCommand + i), HEX); 429 | // Serial.print(" "); 430 | } 431 | Serial.println(); 432 | Serial.flush(); 433 | } 434 | 435 | for(int i = 0; i < commandLength; i++) 436 | { 437 | Serial2.write(*(pCommand + i)); 438 | } 439 | //Serial2.flush(); 440 | nextCommandReady = false; 441 | } 442 | else 443 | { 444 | Serial.print(F("Not ready![")); 445 | for(int i = 0; i < commandLength; i++) 446 | { 447 | Serial.print(*(pCommand + i)); 448 | } 449 | Serial.println(F("]")); 450 | Serial.flush(); 451 | } 452 | } 453 | 454 | 455 | void CheckReceiverBuffer(bool showResponse) 456 | { 457 | if(Serial2.available() > 0) 458 | { 459 | while(Serial2.available()) 460 | { 461 | char charByte = Serial2.read(); 462 | 463 | if(showResponse) 464 | // Serial.print(charByte, HEX); 465 | Serial.write(charByte); 466 | 467 | response[responseIndex] = charByte; 468 | if(response[responseIndex - 1] == '\r' || response[responseIndex - 2] == '\n') 469 | { 470 | //WriteToTerminal(response); 471 | responseReceived = true; 472 | } 473 | responseIndex++; 474 | if(responseIndex >= arraySize) 475 | { 476 | responseIndex = arraySize - 1; 477 | } 478 | } 479 | } 480 | } 481 | 482 | 483 | bool WaitForResponse(bool clearResponse) 484 | { 485 | return WaitForResponse(clearResponse, false); 486 | } 487 | 488 | 489 | bool WaitForResponse(bool clearResponse, bool showResponse) 490 | { 491 | while(!(responseReceived && 492 | (StringContains(response, btResponseOk) || 493 | StringContains(response, btResponseError) || 494 | StringContains(response, btResponseFail)/* || 495 | StringContains(response, F(">"))*/))) 496 | { 497 | CheckReceiverBuffer(showResponse); 498 | } 499 | 500 | bool responseValid = StringContains(response, btResponseOk)/* || 501 | StringContains(response, F("ERROR")) || 502 | StringContains(response, F("FAIL")) || 503 | StringContains(response, F(">"))*/; 504 | 505 | if(clearResponse) 506 | { 507 | memset(response, 0, sizeof(response)); 508 | responseIndex = 0; 509 | } 510 | 511 | nextCommandReady = true; 512 | responseReceived = false; 513 | 514 | if(responseValid) return true; 515 | else return false; 516 | } 517 | 518 | 519 | -------------------------------------------------------------------------------- /SimpleArduinoObd/SimpleArduinoObd.ino: -------------------------------------------------------------------------------- 1 | // Connect to BT OBDII 2 | // Check for connection 3 | // Start getting data 4 | #define DEBUG 1 5 | 6 | #include 7 | #include 8 | #include "FileIO.h" 9 | #include "GpsHelper.h" 10 | #include "ObdHelper.h" 11 | 12 | #define SD_SS_PIN 53 13 | 14 | #define DELAY 1000 // delay between commands in milliseconds 15 | 16 | static bool sendToGraph = false; 17 | 18 | unsigned long timer = 0; 19 | 20 | // Reset function 21 | void (* ResetFunction) (void) = 0; 22 | 23 | void setup() 24 | { 25 | // Setup Comms 26 | Serial.begin(115200); 27 | // Setup SdCard 28 | InitialiseSdCard(SD_SS_PIN); 29 | // Setup Gps 30 | InitialiseGps(); 31 | // Connect to OBD 32 | if(!InitBluetoothComms()) 33 | { 34 | #if DEBUG 35 | Serial.print(F("Failed to connect to OBD")); 36 | #endif 37 | // Sometimes works if it is reset 38 | ResetFunction(); 39 | while(1); 40 | } 41 | 42 | #if DEBUG 43 | Serial.println(F("Bluetooth OK")); 44 | Serial.println(F("Waiting for GPS signal...")); 45 | #endif 46 | // Wait for valid GPS signal 47 | while(!IsGpsDataAvailable(false)); 48 | // Get GPS data 49 | #if DEBUG 50 | Serial.println(F("Acquiring GPS data...")); 51 | #endif 52 | GetGpsData(¤tGpsData); 53 | // Set file name 54 | #if DEBUG 55 | Serial.println(F("Setting filename...")); 56 | #endif 57 | SetFileName( 58 | currentGpsData.year, 59 | currentGpsData.month, 60 | currentGpsData.day, 61 | currentGpsData.hour, 62 | currentGpsData.minute); 63 | 64 | #if DEBUG 65 | Serial.println(F("Now let's rock and roll!")); 66 | #endif 67 | 68 | timer = millis(); 69 | 70 | // Bluetooth - ok 71 | // SD - ok 72 | // FileName - ok 73 | // Now start collecting data 74 | } 75 | 76 | void loop() 77 | { 78 | // Wait for valid GPS data - Should be much less than 1 sec 79 | while(!IsGpsDataAvailable(false)); 80 | GetGpsData(¤tGpsData); 81 | 82 | // Get OBD data 83 | GetObdReadings(¤tObdReading); 84 | 85 | // Save to file 86 | memset(entryArray, 0, sizeof(entryArray)); 87 | char latChar[10] = {0}; 88 | dtostrf(currentGpsData.lat, 4, 6, latChar); 89 | char lonChar[10] = {0}; 90 | dtostrf(currentGpsData.lon, 4, 6, lonChar); 91 | sprintf(entryArray, entryFormat, 92 | currentGpsData.day, currentGpsData.month, currentGpsData.year, 93 | currentGpsData.hour, currentGpsData.minute, currentGpsData.second, 94 | latChar, lonChar, 95 | currentObdReading.RPM, currentObdReading.Speed, currentObdReading.Throttle); 96 | 97 | bool entrySuccess = WriteToFile(entryArray, sizeof(entryArray)); 98 | #if DEBUG 99 | Serial.println(entryArray); 100 | if(entrySuccess) 101 | Serial.println("Entry recorded."); 102 | else 103 | Serial.println("Entry failed"); 104 | #endif 105 | 106 | // Wait until next log interval 107 | while(millis() - timer < DELAY); 108 | timer = millis(); 109 | } 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /SimpleArduinoObd/Strings.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | bool StringContains(const char* charArray, const char* subString) 4 | { 5 | return strstr(charArray, subString) > 0; 6 | } 7 | 8 | bool IsCharHexDigit(char character) 9 | { 10 | if((character >= '0' && character <= '9') || 11 | (character >= 'A' && character <= 'F') || 12 | (character >= 'a' && character <= 'f')) 13 | return true; 14 | else 15 | return false; 16 | } 17 | 18 | byte HexCharToDigit(char character) 19 | { 20 | if(character >= '0' && character <= '9') 21 | return character - '0'; 22 | else if(character >= 'A' && character <= 'F') 23 | return character - 'A' + 10; 24 | else if(character >= 'a' && character <= 'f') 25 | return character = 'a' + 10; 26 | else 27 | return 0; 28 | } 29 | 30 | //#define ARDBUFFER 16 31 | //int ardprintf(char *str, ...) 32 | //{ 33 | // int i, count=0, j=0, flag=0; 34 | // char temp[ARDBUFFER+1]; 35 | // for(i=0; str[i]!='\0';i++) if(str[i]=='%') count++; 36 | // 37 | // va_list argv; 38 | // va_start(argv, count); 39 | // for(i=0,j=0; str[i]!='\0';i++) 40 | // { 41 | // if(str[i]=='%') 42 | // { 43 | // temp[j] = '\0'; 44 | // Serial.print(temp); 45 | // j=0; 46 | // temp[0] = '\0'; 47 | // 48 | // switch(str[++i]) 49 | // { 50 | // case 'd': Serial.print(va_arg(argv, int)); 51 | // break; 52 | // case 'l': Serial.print(va_arg(argv, long)); 53 | // break; 54 | // case 'f': Serial.print(va_arg(argv, double)); 55 | // break; 56 | // case 'c': Serial.print((char)va_arg(argv, int)); 57 | // break; 58 | // case 's': Serial.print(va_arg(argv, char *)); 59 | // break; 60 | // default: ; 61 | // }; 62 | // } 63 | // else 64 | // { 65 | // temp[j] = str[i]; 66 | // j = (j+1)%ARDBUFFER; 67 | // if(j==0) 68 | // { 69 | // temp[ARDBUFFER] = '\0'; 70 | // Serial.print(temp); 71 | // temp[0]='\0'; 72 | // } 73 | // } 74 | // }; 75 | // Serial.println(); 76 | // return count + 1; 77 | //} 78 | 79 | 80 | --------------------------------------------------------------------------------