Clock pod mod with Subarb Select Monitor ECU polling and Arduino
Results 1 to 12 of 12

This is a discussion on Clock pod mod with Subarb Select Monitor ECU polling and Arduino within the Tutorials & DIY forums, part of the Tech & Modifying & General Repairs category; The check engine light: what does it mean!?! I check my engine often; it is always in the same place. ...

  1. #1
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    Clock pod mod with Subarb Select Monitor ECU polling and Arduino

    The check engine light: what does it mean!?!
    I check my engine often; it is always in the same place. Go away, stupid light.

    As my car continues to age ungracefully, I am seeing this light come on with increasing frequency. When Iím out driving I donít necessarily have my laptop on me and a car parts store may not be nearby- a quick code check is not available. Should I have my car towed for what has lately been a P0420?
    I donít think so.
    Thus, I have been motivated to integrate the simple CEL code-reading functionality of learning view into my car.
    But why stop there: if I am going to be communicating with the ECU to pull the codes, why not build a sensor/memory polling mechanism too?
    Thus, my project is a simple LCD display, powered by an Arduino Uno which communicates over the OBD II connection using the Subaru Select Monitor (SSM) protocol.



    The plan for the end product is to
    -Integrate with the carís design in an unobtrusive manner: in the clock pod
    -replicate the original function of the clock pod: display the time
    - monitor a few interesting parameters:
    1) intake air temperature: I chose this since my car, unlike many new cars, does not have an exterior temperature thermometer
    2) Injector duty cycle: I have been having fuel learning issues, so I want to know if Iím reaching into the upper ranges of my injectors. Plus this is a pseudo-measure of in-use power.
    3) boost: my car came without a boost gauge.
    -read and display check engine light codes when the light is on in the dash display.

    This thread is a documentation of the development process rather than a tutorial; however I do intend to include all of the details which would enable anyone else to replicate this mod.
    David - '05 WRX

  2. Remove Advertisements
    ClubWRX.net
    Advertisements
     

  3. #2
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    Integration with the Car

    I want this mod to look nice (note: this doesnít mean that Iím going to do a clean job, but the intention is good). The stock clock pod is an excellent size to fit a small LCD.


    I chose to use the Sparkfun Serial LCD Kit because the size of the LCD almost perfectly fits into the opening.
    I trimmed slots for the PCB to fit into, careful to maintain the clips for the original clock pod in case I ever want to revert, and twist tied the LCD in place. I also made a simple bezel with paint and some plastic packaging, and placed this in front of the LCD.

    One more thing: since the clock pod face plate was very well attached (I used much more force removing this clipped in piece than I would have liked), I trimmed the points off of the front clips using a hack saw (they still clip, but not quite as difficult to remove now).
    I installed the Arduino (with the custom shield, more on this below) and LCD into the clock area by running the USB cable down to the 12V power port (to power the arduino), running a wire down to the OBD II port (for signal), and connecting a lead to the ACC (+12V) line of the clock power dongle (as a signal pull-up line).
    I just closed the cover over this, leaving the parts to slide around- after all, what is one more rattle?

    Although the Arduino UNO can be powered with anywhere between 5-19V (i.e., it could be powered through the clock dongle), I chose to power it though USB by splicing a 12V to USB adapter into the 12V power/cig lighter. I chose this route so that I could program the Arduino (this is done over USB) by simply lifting the shifter boot and pulling out the USB cable.


    As a temporary solution, I spliced a line into the OBD II K-line (ISO 9141-2 comms) thinking that this would allow for simple communications. It turns out that the communications donít work without problems yet: I need to have my VAG-Com cable plugged in or else the communications wonít work. This means that my circuit is not finished.
    David - '05 WRX

  4. #3
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    Hardware

    I found a few references which show that SSM uses a version of ISO 9141 communication- hence it shares data send and receive on a single line, serial communications (UART) at 4800 baud. It communicates at 12V, but the Arduino communicates at 5V.
    Although the Arduino has libraries built in which allow for serial communication, it is designed with separate transmission (Tx) and receive (Rx) lines. These lines idle with high voltage, and pull low to signal. In order to share them, and to communicate at 12V I’ve designed a simple circuit:

    Currently, I’m using the software serial library in order to have multiple serial ports on the Arduino- this enables me to use separate serial communication to command the LCD, to troubleshoot with the Serial monitor in the Arduino (as well as program the Arduino without unplugging it) and to run the SSM communications.

    I also purchased a simple real time clock kit from digispark. It communicates using the I2C bus on the arduino, and is a simple solution which allows me to keep track of time, even when power is removed (+1: now I don't lose time when the battery is pulled; -1: now I have to use a laptop to set the time on the clock in the car).

    A note on soldering: it seems that my messy soldering (lots of flux everywhere) creates rather dirty circuits which can drastically affect the performance of the communication or of the crystal on the clock module. I washed the circuit with soapy toothbrush scrubbing so that everything worked.

    This is all fine, for now, but the communications only work with the car when the VAG com cable is plugged in. That means there will be a revision to the circuit in the future.
    Last edited by Obeisance; 07-17-2014 at 11:49 AM.
    David - '05 WRX

  5. #4
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    Communication Ė reverse engineering the reverse engineered software

    Before taking on this project, I knew nothing about serial communication. I tried to find tutorials on teh interwebs, but I didn’t easily find anything. Even on the romraider forums. Thus, I sought to intercept the packets which the romraider logger and learning view sent out when it was trying to communicate with the car. This way, I could at least try and send the same packets.
    My first stroke of luck was the log file which learning view leaves: it showed the ECU init packet as well as the response (and even the packet which needs to be sent to read CELs):
    WRITE 6 bytes: 80 10 F0 01 BF 40
    READ 68 bytes: 80 10 F0 01 BF 40 80 F0 10 39 FF A2 10 0F 3E 14 48 40 06 73 FA EB A2 2B C1 02 AA 00 10 00 60 CE 54 F8 B1 E4 80 00 E0 00 00 00 00 00 DC 00 00 45 1F 00 00 02 00 00 00 03 00 00 E0 00 00 00 00 00 00 00 00 8F
    ECU supported (ECUID:3E14484006 CALID:A4TF800F DESC:05 USDM Impreza WRX MT)
    Thus, I connected the Arduino to the K-line (pin 7) of the vag com cable, and powered it (line 16) and tried to pretend that the Arduino was the ECU:

    I even spoofed the ECU response, and was able to get learning view to communicate with the Arduino.
    I took another step, and was able to read packets from romraider (now as decimals instead of hexadecimal bytes:
    IAT: 128 16 240 8 168 0 0 0 18 0 0 100 166
    IDC: 128 16 240 14 168 0 0 0 32 0 0 14 0 0 15 0 0 100 215
    Boost (manifold relative pressure direct): 128 16 240 11 168 0 2 24 32 2 24 33 0 0 100 12

    As it turns out, the logger definitions show these addresses, and how to convert them to numbers:
    <parameter id="P11" name="Intake Air Temperature" desc="P11" ecubyteindex="9" ecubit="5" target="1">
    <address>0x000012</address>
    <conversions>
    <conversion units="C" expr="x-40" format="0" gauge_min="-20" gauge_max="60" gauge_step="10" />
    <conversion units="F" expr="32+9*(x-40)/5" format="0" gauge_min="0" gauge_max="140" gauge_step="20" />
    </conversions>
    </parameter>
    This shows that (hex) 0x000012, or (dec) 0 0 18 is the address for the IAT. The byte (decimal) returned should have 40 subtracted from it in order to give the IAT in Celcius.

    My circuit is even able to eavesdrop on the response from the ECU when installed in the car:
    Romraider request for IAT: 128 16 240 5 168 0 0 0 18 63
    ECU response: 128 240 16 2 232 84 190
    That gives 84 – 40 = 44 C as the intake temperature (a tad hot, but this was after a long drive and the engine bay had a bit of heatsoak).

    I’ve used this process to design the packet I sent to ask for the IAT, Manifold relative pressure (MRP), the injector duty cycle (IDC), and the CEL light status:
    It turns out that IAT requests one address, IDC requests 3 (two for engine speed, one for the injector pulse width that includes the latency), MRP requests two (manifold pressure and atmos pressure), and the CEL status requests one value.
    ECU poll: 128 16 240 23 168 0 2 24 32 2 24 33 0 0 18 0 0 32 0 0 14 0 0 15 0 1 150 154
    Bytes Translated: [begin packet, to ECU, from diagnostics tool, 23 bytes of data, A8- the read single address byte, set to 1 for fast polling, MRP, MRP, MRP, MRP, MRP, MRP, IAT, IAT, IAT, IDC, IDC, IDC, IDC, IDC, IDC, IDC, IDC, IDC, CEL, CEL, CEL, checksum]
    Last edited by Obeisance; 07-07-2014 at 08:14 PM.
    David - '05 WRX

  6. #5
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    Programming

    This is an unfinished version which does not yet display CELs. It turns out that the limited memory in the Arduino UNO is a bit of a hinderance. In order to overcome this, Iíve attempted to use program memory to store the CEL character strings. Further, Iíve borrowed some code which should enable me to watch how much RAM of the 2K I have free during the run (large arrays and many variables can eat this up fast).

    Also, Thank goodness for the romraider logger definitions and that community, since they've already answered many of my issues through their development.

    Updated: 2014-07-07
    Code:
    #include <Wire.h>
    #include <SoftwareSerial.h>
    #include "RTClib.h"
    #include "DTC_arrays.h"
    
    /*
    This code should allow for interfacing with Subaru ECUs
    The intention is to pull DTC's and display them on an
    LCD. There will also be functionality to display the time
    from a clock module and to adjust the time.
    
    Some of the clock code came from the RTClib ds1307 example
    */
    
    SoftwareSerial sendSerial = SoftwareSerial(10,11); //Rx, Tx
    SoftwareSerial lcd = SoftwareSerial(8,9);
    RTC_DS1307 rtc;
    int mem = freeRam();
    
    //ECU variables
    byte ecuInit[6] = {128,16,240,1,191,64};
    /*byte ecuInitResponse[62] = {128,240,16,57,255,162,16,15,62,
    20,72,64,6,115,250,235,162,43,193,2,170,0,16,0,96,206,84,248,177,
    228,128,0,224,0,0,0,0,0,220,0,0,69,31,0,0,2,0,0,0,3,0,0,224,0,0,0,
    0,0,0,0,0,143};*/ // 62 bytes
    byte readDTCTemp1[] = {128,16,240,98,168,0,0,0,142,0,0,143,0,0,144,0,0,145,0,0,146,0,0,147,0,0,148,0,0,149,0,0,150,0,0,151,0,0,152,0,0,153,0,0,154,0,0,155,0,0,156,0,0,157,0,0,158,0,0,159,0,0,160,0,0,161,0,0,162,0,0,163,0,0,164,0,0,165,0,0,166,0,0,167,0,0,168,0,0,169,0,0,170,0,0,171,0,0,172,0,0,173,58};
    byte readDTCTemp2[] = {128,16,240,68,168,0,0,0,240,0,0,241,0,0,242,0,0,243,0,1,35,0,1,36,0,1,37,0,1,38,0,1,39,0,1,40,0,1,41,0,1,42,0,1,80,0,1,81,0,1,82,0,1,83,0,1,84,0,1,96,0,1,97,0,1,98,0,1,99,0,1,100,252};
    byte readDTCMem1[] = {128,16,240,98,168,0,0,0,174,0,0,175,0,0,176,0,0,177,0,0,178,0,0,179,0,0,180,0,0,181,0,0,182,0,0,183,0,0,184,0,0,185,0,0,186,0,0,187,0,0,188,0,0,189,0,0,190,0,0,191,0,0,192,0,0,193,0,0,194,0,0,195,0,0,196,0,0,197,0,0,198,0,0,199,0,0,200,0,0,201,0,0,202,0,0,203,0,0,204,0,0,205,58};
    byte readDTCMem2[] = {128,16,240,68,168,0,0,0,244,0,0,245,0,0,246,0,0,247,0,1,43,0,1,44,0,1,45,0,1,46,0,1,47,0,1,48,0,1,49,0,1,50,0,1,85,0,1,86,0,1,87,0,1,88,0,1,89,0,1,101,0,1,102,0,1,103,0,1,104,0,1,105,126};
    byte pollECUbytes[] = {128,16,240,23,168,0,2,24,32,2,24,33,0,0,18,0,0,32,0,0,14,0,0,15,0,1,150,154};
    //[mrp,mrp,iat,idc,idc,idc,mil]
    int ECUbytes[7] = {0,0,0,0,0,0,0};
    int DTC[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
    int DTCFlag1[][2] = {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
    int DTCFlag2[][2] = {{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
    
    
    void setup() 
    { 
      Serial.begin(9600); //for diagnostics
      lcd.begin(9600); //somehow, this must begin before sendSerial or else ECU comms fail
      sendSerial.begin(4800); //SSM uses 4800 8N1 baud rate
      
      //one time turn off the lcd splash screen
      //setSplashScreen();
      
      //one time adjust backlight to max
      //setBacklight(255);
      
      //one time change the LCD baud rate to 9600
      //lcd.write(0x81);
      //lcd.write(4);
      //delay(1000);
      
      lcdStartupMessage();
      
      Wire.begin();
      rtc.begin();
      //in order to update the time without pulling the battery, uncomment this code
      //then recomment the code and re-upload the code
      //rtc.adjust(DateTime(__DATE__, __TIME__));
      if (! rtc.isrunning()) {
        Serial.println("RTC is NOT running!");
        // following line sets the RTC to the date & time this sketch was compiled
        rtc.adjust(DateTime(__DATE__, __TIME__));
        setLCDCursor(0);
        lcd.print("repl. clk batt., re-upload code");
        delay(10000);
        clearDisplay;
      
      }
      
      //diagnostic: check free ram
      Serial.print("ram before setup: ");
      Serial.println(mem);
      mem = freeRam();
      Serial.print("ram in setup: ");
      Serial.println(mem);
    } 
    
    
    //Variables for ECU communication
    boolean ecuInitCheck = false;
    boolean ecuPollCheck = true;
    boolean MILon = false;
    boolean MILread = false;
    int IATbyte = 0;
    int IDCbyteIPW = 0;
    int IDCbyteRPM1 = 0;
    int IDCbyteRPM2 = 0;
    int MRPbyteAtm = 0;
    int MRPbyteMani = 0;
    byte MILbyte = 0;
    
    //Timekeeping variables
    byte minTimeNext = 0;
    
    void loop() 
    {
      mem = freeRam();
      Serial.print("ram in main: ");
      Serial.println(mem);
      //We'll first get the clock information onto the first 5 LCD spots
      updateTime();
      
      //then, check to see if the ECU communications have been initiated (this step may not be necessary)
      if(ecuInitCheck == false)
      {
        Serial.println("Sending ECU init");
        writeSSM(ecuInit, 6, sendSerial);
        
        if(readECU(ECUbytes, 7, false) == true)
        {
          Serial.println("ecu init success");
          ecuInitCheck = true;
        }
      }
      
      if(MILon == true && MILread == false)
      {
        Serial.println("Reading CELs");
        writeSSM(readDTCTemp1, 103, sendSerial);
        readECU(DTC, 10, true);
        DTCread(DTC, 10, DTCFlag1, 10, 1);
        writeSSM(readDTCTemp2, 73, sendSerial);
        readECU(DTC, 10, true);
        DTCread(DTC, 10, DTCFlag2, 10, 2);
        writeSSM(readDTCMem1, 103, sendSerial);
        readECU(DTC, 10, true);
        DTCread(DTC, 10, DTCFlag1, 10, 1);
        writeSSM(readDTCMem2, 73, sendSerial);
        readECU(DTC, 10, true);
        DTCread(DTC, 10, DTCFlag2, 10, 2);
        
        MILread == true;
      }
      else if(MILon == true && MILread == true)
      {
        Serial.println("Displaying CELs");
        DTCupdate(DTCFlag1, 10, 1);
        delay(2000);
        DTCupdate(DTCFlag2, 10, 2);
        delay(2000);
      }
      else if(ecuInitCheck == true)
      {
        Serial.println("polling ecu");
        writeSSM(pollECUbytes, 28, sendSerial);
        if(readECU(ECUbytes, 7, false) == false)
        {
          Serial.println("ecu poll fail");
          //ecuInitCheck = false; //to re-send the init if ecuPolling fails- this is not necessary
          ecuPollCheck = false;
        }
        else
        {
          ecuPollCheck = true;
        }
        
        //interpret and display the ECU data on the LCD
        if(ecuPollCheck == true)
        {
        MRPbyteAtm = ECUbytes[0];
        //Serial.print("MRPbyteAtm: ");
        //Serial.println(MRPbyteAtm);
        MRPbyteMani = ECUbytes[1];
        //Serial.print("MRPbyteMani: ");
        //Serial.println(MRPbyteMani);
        IATbyte = ECUbytes[2];
        //Serial.print("IATbyte: ");
        //Serial.println(IATbyte);
        IDCbyteIPW = ECUbytes[3];
        //Serial.print("IDCbyteIPW: ");
        //Serial.println(IDCbyteIPW);
        IDCbyteRPM1 = ECUbytes[4];
        //Serial.print("IDCbyteRPM1: ");
        //Serial.println(IDCbyteRPM1);
        IDCbyteRPM2 = ECUbytes[5];
        //Serial.print("IDCbyteRPM2: ");
        //Serial.println(IDCbyteRPM2);
        MILbyte = ECUbytes[6];
        //Serial.print("MILbyte: ");
        //Serial.println(MILbyte);
        MILbyte = bitRead(MILbyte,7); //the 7th bit of this address byte indicates whether the MIL is on
        if(MILbyte == 1){
          //MILon = true;
          Serial.println("DTC light on");
        }
       
        int IAT = computeIAT(IATbyte);
        updateTemp(IAT);
        
        int IDC = computeIDC(IDCbyteIPW, IDCbyteRPM1, IDCbyteRPM2);
        updateIDC(IDC);
        
        float MRP = computeMRP(MRPbyteAtm, MRPbyteMani);
        updateBoost(MRP);
        }
      }
    
    }
    
    
    /* returns the 8 least significant bits of an input byte*/
    byte CheckSum(byte sum){
      byte counter = 0;
      byte power = 1;
      for(byte n = 0; n < 8; n++){
        counter += bitRead(sum,n)*power;
        power = power*2;
      }
      return counter;
    }
    
    /*writes data over the software serial port
    the &digiSerial passes a reference to the external
    object so that we can control it outside of the function*/
    void writeSSM(byte data[], byte length, SoftwareSerial &digiSerial){
      //Serial.println("Sending packet... ");
      for(byte x = 0; x < length; x++){
        digiSerial.write(data[x]);
      }
      //Serial.println("done sending.");
    }
    
    /*LCD Functions borrowed from: https://www.sparkfun.com/tutorials/289 
    Some other character options:
    0◊0D, will advance the cursor to the next row
    0◊09, will advance the cursor 5 places
    0◊08, will operate as a standard backspace
    */
    void setBacklight(byte brightness)
    {
      lcd.write(0x80);  // send the backlight command, decimal 128
      lcd.write(brightness);  // send the brightness value 0-255
    }
    
    void clearDisplay()
    {
      lcd.write(0xFE);  // send the special command
      lcd.write(0x01);  // send the clear screen command
    }
    
    void setLCDCursor(byte cursor_position)
    {
      lcd.write(0xFE);  // send the special command
      lcd.write(0x80);  // send the set cursor command
      lcd.write(cursor_position);  // send the cursor position 0-31, 0 is top left
    }
    
    void setSplashScreen()
    {
      lcd.write(0xFE);  // send the special command
      lcd.write(0x1E);  // toggle the splash screen appearance
    }
    
    void scrollScreenRight()
    {
      lcd.write(0xFE);  // send the special command
      lcd.write(0x1C);  // moves everything right by one
    }
    
    void scrollScreenleft()
    {
      lcd.write(0xFE);  // send the special command
      lcd.write(0x18);  // moves everything left by one
    }
    
    void lcdStartupMessage()
    {
      clearDisplay();
      setLCDCursor(3);
      lcd.print("Hello Dave");
      delay(4000);
      clearDisplay();
    }
    /*********************************************************/
    David - '05 WRX

  7. #6
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    code, cont.

    Code:
    void updateTime()
    {
      DateTime now = rtc.now();
      byte hourTime = now.hour();
      byte minTime = now.minute();
      
      if(minTimeNext != minTime){
        setLCDCursor(0);
        if(hourTime > 12){
          hourTime = hourTime - 12;
          lcd.print(" ");
        }
        lcd.print(hourTime);
        Serial.print(hourTime);
        lcd.print(':');
        Serial.print(':');
        if(minTime < 10)
        lcd.print("0");
        lcd.print(minTime);
        lcd.print(" ");
        Serial.println(minTime);
        minTimeNext = minTime;
      }
    }
    
    void updateBoost(float boostValue)
    {
      //display the boost value on the lower left of the lcd
      setLCDCursor(16);
      if(boostValue >= 0.0 && boostValue < 10.0)
      {
        lcd.print(" ");
        lcd.print(boostValue,1); //print one digit of the float value
        Serial.print(boostValue);
      }
      else
      {
        lcd.print(boostValue,1);
        Serial.print(boostValue);
      }
      setLCDCursor(20);
      lcd.print("psi");
      Serial.println("psi");
      /*display graphical gauge on lower right, 
      using blocks "0xFF" and a bar "0x7C" at 0 
      0xFE clears a cell*/
      setLCDCursor(23);
      lcd.print("         "); //clear the plot
      int value = ((int)boostValue+11) / 3;
      for(int y = 0; y <= value; y++)
      {
        setLCDCursor(31-y);
        lcd.print((char)255); //0xFF, the filled space character
      }
      setLCDCursor(28);
      lcd.print((char)124);  //0x7C, the | character
    }
    
    void updateTemp(int tempValue)
    {
      setLCDCursor(6);
      if(tempValue >= 0)
      lcd.print(" ");
      lcd.print(tempValue);
      lcd.print((char)223); //degree sign
      lcd.print("C ");
      Serial.print(tempValue);
      Serial.println("C");
    }
    
    void updateIDC(int idcValue)
    {
      setLCDCursor(12);
      if(idcValue < 100)
      lcd.print(" ");
      if(idcValue < 10);
      lcd.print(" ");
      lcd.print(idcValue);
      lcd.print((char)37); //percent character
      Serial.print(idcValue);
      Serial.println("%");
    }
    
    
    /* *********************************************************
     Packets must follow this structure:
    
    0x80
    Destination byte
    Source byte
    Data size byte
    data..
    
    Checksum byte
    
    Data size byte specities the number of data bytes in
    the packet
    
    Checksum byte is the 8 least significant bits of the
    sum of every packet byte (including the header)
    
    see: http://www.romraider.com/RomRaider/SsmProtocol
    ************************************************************ */
    //this will change the values in dataArray, populating them with values respective of the poll array address calls
    boolean readECU(int* dataArray, byte dataArrayLength, boolean nonZeroes)
    {
      byte data = 0;
      boolean isPacket = false;
      byte sumBytes = 0;
      byte checkSumByte = 0;
      byte dataSize = 0;
      byte bytePlace = 0;
      byte zeroesLoopSpot = 0;
      byte loopLength = 4;
      for(byte j = 0; j < loopLength; j++)
      {
        data = sendSerial.read();
        Serial.print("data: "); //diagnostic: shows any data stream
        Serial.println(data);  //somehow, the delay? from these diagnostic lines allows the program to work..
      
        if(data == 128 && dataSize == 0){  //0x80 or 128 marks the beginning of a packet
         isPacket = true;
         Serial.println("Begin Packet");
         j = 0;
        }
        
        //terminate function and return false if no response is detected
        if(j == (loopLength - 1) && isPacket != true)
        {
          Serial.println("booted 1");
          return false;
        }
      
       if(isPacket == true && data != -1){
         Serial.println(data); // for debugging: shows in-packet data
       
         if(bytePlace == 3){ // how much data is coming
           dataSize = data;
           //Serial.print("dataSize: ");
           //Serial.println(dataSize);
           loopLength = data + 6;
         }  
         
         if(bytePlace > 4 && bytePlace-5 < dataArrayLength && nonZeroes == false)
         {
           dataArray[bytePlace-5] = data;
         }
         else if(bytePlace > 4 && zeroesLoopSpot < dataArrayLength/2 && nonZeroes == true && data != 0)
         {
           dataArray[zeroesLoopSpot] = data;
           dataArray[zeroesLoopSpot + (dataArrayLength / 2)] = bytePlace;
           zeroesLoopSpot++;
         }
             
         bytePlace += 1; //increment bytePlace
       
         //once the data is all recieved, checksum and re-set counters
         if(bytePlace == dataSize+5){
           checkSumByte = CheckSum(sumBytes);  //the 8 least significant bits of sumBytes
         
           if(data != checkSumByte){
             Serial.println("checksum error");
             return false;
           }
         
           isPacket = false;
           sumBytes = 0;
           bytePlace = 0;
           checkSumByte = 0;
           dataSize = 0;
           Serial.println("End Packet");
           return true;
         }
         else{
           sumBytes += data; // this is to compare with the checksum byte
           //Serial.print("sum: ");
           //Serial.println(sumBytes);
         }
       }
      }
    }
    
    //input the DTC flags, with half the array as the DTC flag number and the other half as the address
    //This function will change DTCs[] to include the error code addresses: [address][byte], but not overwrite or duplicate values
    void DTCread(int flags[], int flagLength, int DTCs[][2], int DTCsLength, int DTCTableNumber)
    {
      int DTCconvoluted = 0;
      int DTCaddr = 0;
      int index = 0;
      boolean duplicate = false;
      
      for(int plus = 0; plus < DTCsLength; plus++);
      {
        if(DTCs[index][0] != -1)
        index++;
      }
      
      for(int i = 0; i < flagLength/2; i++)
      {
        if(flags[i] != -1)
        {
          DTCconvoluted = flags[i];
          DTCaddr = flags[i + flagLength/2] - 6;
          for(int f = 0; f < 8; f++)
          {
            if(bitRead(DTCconvoluted, f) != 0 && index < DTCsLength);
            {
              //loop to check if this value is already present in DTCs
              for(int pres = 0; pres < DTCsLength; pres++)
              {
                if(DTCs[pres][0] == DTCaddr && DTCs[pres][1] == f)
                {
                  duplicate = true;
                }
              }
              if(duplicate == false)
              {
                DTCs[index][0] = DTCaddr;
                DTCs[index][1] = f;
                index++;
              }
              duplicate = false;
            }
          }
        }
      }
      DTCupdate(DTCs, DTCsLength, DTCTableNumber);
      delay(2000);
    }
    
    //This function takes in an array of DTC addresses, and reads off the string values from PROGMEM
    //Finally, it displays them on an LCD and the serial monitor. Values of '-1' are ignored. DTCTableNumber is 1 or 2.
    void DTCupdate(int DTCs[][2], byte DTCsLength, byte DTCTableNumber)
    {
      char buffer[5];
      byte DTCcount = 0;
      
      for(byte a = 0; a < DTCsLength; a++)
      {
        byte b = DTCs[a][0];
        byte c = DTCs[a][1];
        if(DTCs[a][0] != -1 && DTCTableNumber == 1)
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(DTCset1[b][c])));
        }
        else if(DTCs[a][0] != -1 && DTCTableNumber == 2)
        {
          strcpy_P(buffer, (char*)pgm_read_word(&(DTCset2[b][c])));
        }
        Serial.println(buffer);
        setLCDCursor(5+DTCcount);
        lcd.print(buffer);
        DTCcount += 6;
      }
    }
    
    int computeIAT(int IAT)
    {
      int temperature = IAT - 40;
      return temperature;
    }
    
    float computeMRP(int atmos, int maniPres)
    {
      float atmosCor = (atmos-128)*37/255;
      float maniPresCor = (maniPres-128)*37/255;
      float MRP = maniPresCor - atmosCor;
      return MRP;
    }
    
    int computeIDC(int IPW, int rpm1, int rpm2)
    {
      int rpm = (rpm1*100) + rpm2;
      float IPWcor = (IPW*256/1000);
      float injectPerSec = rpm/120;
      int IDC = (IPWcor*injectPerSec)/10;
      return IDC;
    }
    
    //returns the amount of free memory for variable use out of the 2k on the UNO
    //from: https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory
    int freeRam ()
    {
      extern int __heap_start, *__brkval;
      int v;
      return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
    }
    David - '05 WRX

  8. #7
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    code, cont. 2

    For DTCarrays.h
    Code:
    /*these are adopted from the romraider logger definitions v253
    use PROGMEM to save variable space except for the active DTCs
    A 3D array, with the 1st index set the same as the request order 
    of the ECU calls to tempDTCs and memDTCs addresses, the second
    index set to the bit position of the DTC address, and the third
    as the DTC code chars */
    
    prog_char P0335[] PROGMEM = "P0335";
    prog_char unkn[] PROGMEM = "unkn";
    prog_char P0336[] PROGMEM = "P0336";
    prog_char P0341[] PROGMEM = "P0341";
    prog_char P0340[] PROGMEM = "P0340";
    prog_char P0604[] PROGMEM = "P0604";
    prog_char P0601[] PROGMEM = "P0601";
    
    //0x0000AE and temp 0x00008E
    //PROGMEM const char *addr0x0000AE[] = {P0335,unkn,P0336,P0341,P0340,unkn,P0604,P0601};
    
    prog_char P0102[] PROGMEM = "P0102";
    prog_char P0103[] PROGMEM = "P0103";
    prog_char P1141[] PROGMEM = "P1141";
    prog_char P0101[] PROGMEM = "P0101";
    prog_char P0500[] PROGMEM = "P0500";
    prog_char P1540[] PROGMEM = "P1540";
    prog_char P0332[] PROGMEM = "P0332";
    prog_char P0333[] PROGMEM = "P0333";
    
    //0x0000AF and temp 0x00008F
    //PROGMEM const char *addr0x0000AF[] = {P0102,P0103,P1141,P0101,P0500,P1540,P0332,P0333};
    
    prog_char P0325[] PROGMEM = "P0325";
    prog_char P0330[] PROGMEM = "P0330";
    prog_char P0327[] PROGMEM = "P0327";
    prog_char P0328[] PROGMEM = "P0328";
    prog_char P0122[] PROGMEM = "P0122";
    prog_char P0123[] PROGMEM = "P0123";
    prog_char P1142[] PROGMEM = "P1142";
    prog_char P0121[] PROGMEM = "P0121";
    
    //0x0000B0 and temp 0x000090
    //PROGMEM const char *addr0x0000B0[] = {P0325,P0330,P0327,P0328,P0122,P0123,P1142,P0121};
    
    prog_char P0117[] PROGMEM = "P0117";
    prog_char P0118[] PROGMEM = "P0118";
    prog_char P0464[] PROGMEM = "P0464";
    prog_char P0125[] PROGMEM = "P0125";
    prog_char P0462[] PROGMEM = "P0462";
    prog_char P0463[] PROGMEM = "P0463";
    prog_char P0461[] PROGMEM = "P0461";
    prog_char P1442[] PROGMEM = "P1442";
    
    //0x0000B1 and temp 0x000091
    //PROGMEM const char *addr0x0000B1[] = {P0117,P0118,P0464,P0125,P0462,P0463,P0461,P1442};
    
    prog_char P0107[] PROGMEM = "P0107";
    prog_char P0108[] PROGMEM = "P0108";
    prog_char P0143[] PROGMEM = "P0143";
    prog_char P0144[] PROGMEM = "P0144";
    prog_char P0106[] PROGMEM = "P0106";
    prog_char P0350[] PROGMEM = "P0350";
    prog_char P1518[] PROGMEM = "P1518";
    prog_char P0512[] PROGMEM = "P0512";
    
    //0x0000B2 and temp 0x000092
    //PROGMEM const char *addr0x0000B2[] = {P0107,P0108,P0143,P0144,P0106,P0350,P1518,P0512};
    
    prog_char P0452[] PROGMEM = "P0452";
    prog_char P0453[] PROGMEM = "P0453";
    prog_char P0451[] PROGMEM = "P0451";
    prog_char P1237[] PROGMEM = "P1237";
    prog_char P1238[] PROGMEM = "P1238";
    prog_char P1239[] PROGMEM = "P1238";
    prog_char P1240[] PROGMEM = "P1240";
    
    //0x0000B3 and temp 0x000093
    //PROGMEM const char *addr0x0000B3[] = {P0452,P0453,unkn,P0451,P1237,P1238,P1239,P1240};
    
    prog_char P1590[] PROGMEM = "P1590";
    prog_char P1591[] PROGMEM = "P1591";
    prog_char P1592[] PROGMEM = "P1592";
    prog_char P0851[] PROGMEM = "P0851";
    prog_char P0182[] PROGMEM = "P0182";
    prog_char P0183[] PROGMEM = "P0183";
    prog_char P0181[] PROGMEM = "P0181";
    prog_char P0852[] PROGMEM = "P0852";
    
    //0x0000B4 and temp 0x000094
    //PROGMEM const char *addr0x0000B4[] = {P1590,P1591,P1592,P0851,P0182,P0183,P0181,P0852};
    
    prog_char P1510[] PROGMEM = "P1510";
    prog_char P1511[] PROGMEM = "P1511";
    prog_char P1512[] PROGMEM = "P1512";
    prog_char P1513[] PROGMEM = "P1513";
    prog_char P1514[] PROGMEM = "P1514";
    prog_char P1515[] PROGMEM = "P1515";
    prog_char P1516[] PROGMEM = "P1516";
    prog_char P1517[] PROGMEM = "P1517";
    
    //0x0000B5 and temp 0x000095
    //PROGMEM const char *addr0x0000B5[] = {P1510,P1511,P1512,P1513,P1514,P1515,P1516,P1517};
    
    prog_char P1492[] PROGMEM = "P1492";
    prog_char P1493[] PROGMEM = "P1493";
    prog_char P1494[] PROGMEM = "P1494";
    prog_char P1495[] PROGMEM = "P1495";
    prog_char P1496[] PROGMEM = "P1496";
    prog_char P1497[] PROGMEM = "P1497";
    prog_char P1498[] PROGMEM = "P1498";
    prog_char P1499[] PROGMEM = "P1499";
    
    //0x0000B6 and temp 0x000096
    //PROGMEM const char *addr0x0000B6[] = {P1492,P1493,P1494,P1495,P1496,P1497,P1498,P1499};
    
    prog_char P1102[] PROGMEM = "P1102";
    prog_char P1122[] PROGMEM = "P1122";
    prog_char P1446[] PROGMEM = "P1446";
    prog_char P1447[] PROGMEM = "P1447";
    prog_char P1090[] PROGMEM = "P1090";
    prog_char P1091[] PROGMEM = "P1091";
    prog_char P1092[] PROGMEM = "P1092";
    prog_char P1093[] PROGMEM = "P1093";
    
    //0x0000B7 and temp 0x000097
    //PROGMEM const char *addr0x0000B7[] = {P1102,P1122,P1446,P1447,P1090,P1091,P1092,P1093};
    
    prog_char P0508[] PROGMEM = "P0508";
    prog_char P0509[] PROGMEM = "P0509";
    prog_char P1507[] PROGMEM = "P1507";
    prog_char P0506[] PROGMEM = "P0506";
    prog_char P0507[] PROGMEM = "P0507";
    prog_char P1698[] PROGMEM = "P1698";
    prog_char P1699[] PROGMEM = "P1699";
    prog_char P1448[] PROGMEM = "P1448";
    
    //0x0000B8 and temp 0x000098
    //PROGMEM const char *addr0x0000B8[] = {P0508,P0509,P1507,P0506,P0507,P1698,P1699,P1448};
    
    prog_char P0444[] PROGMEM = "P0444";
    prog_char P0445[] PROGMEM = "P0445";
    prog_char P0691[] PROGMEM = "P0691";
    prog_char P0692[] PROGMEM = "P0692";
    prog_char P0480[] PROGMEM = "P0480";
    prog_char P1480[] PROGMEM = "P1480";
    prog_char P0483[] PROGMEM = "P0483";
    prog_char P0864[] PROGMEM = "P0864";
    
    //0x0000B9 and temp 0x000099
    //PROGMEM const char *addr0x0000B9[] = {P0444,P0445,P0691,P0692,P0480,P1480,P0483,P0864};
    
    prog_char P0365[] PROGMEM = "P0365";
    prog_char P0390[] PROGMEM = "P0390";
    prog_char P0011[] PROGMEM = "P0011";
    prog_char P0021[] PROGMEM = "P0021";
    prog_char P1400[] PROGMEM = "P1400";
    prog_char P1420[] PROGMEM = "P1420";
    prog_char P0458[] PROGMEM = "P0458";
    prog_char P0459[] PROGMEM = "P0459";
    
    //0x0000BA and temp 0x00009A
    //PROGMEM const char *addr0x0000BA[] = {P0365,P0390,P0011,P0021,P1400,P1420,P0458,P0459};
    
    prog_char P0865[] PROGMEM = "P0865";
    prog_char P0866[] PROGMEM = "P0866";
    prog_char P1443[] PROGMEM = "P1443";
    prog_char P1559[] PROGMEM = "P1559";
    prog_char P0661[] PROGMEM = "P0661";
    prog_char P0662[] PROGMEM = "P0662";
    prog_char P0447[] PROGMEM = "P0447";
    prog_char P0448[] PROGMEM = "P0448";
    
    //0x0000BB and temp 0x00009B  
    //PROGMEM const char *addr0x0000BB[] = {P0865,P0866,P1443,P1559,P0661,P0662,P0447,P0448};
    
    prog_char P0720[] PROGMEM = "P0720";
    prog_char P0725[] PROGMEM = "P0725";
    prog_char P1700[] PROGMEM = "P1700";
    prog_char P0710[] PROGMEM = "P0710";
    prog_char P0705[] PROGMEM = "P0705";
    prog_char P1701[] PROGMEM = "P1701";
    prog_char P0703[] PROGMEM = "P0703";
    prog_char P0741[] PROGMEM = "P0741";
    
    //0x0000BC and temp 0x00009C 
    //PROGMEM const char *addr0x0000BC[] = {P0720,P0725,P1700,P0710,P0705,P1701,P0703,P0741};
    
    prog_char P0753[] PROGMEM = "P0753";
    prog_char P0758[] PROGMEM = "P0758";
    prog_char P1706[] PROGMEM = "P1706";
    prog_char P0748[] PROGMEM = "P0748";
    prog_char P0743[] PROGMEM = "P0743";
    prog_char P0731[] PROGMEM = "P0731";
    prog_char P0732[] PROGMEM = "P0732";
    prog_char P0733[] PROGMEM = "P0733";
    
    //0x0000BD and temp 0x00009D 
    //PROGMEM const char *addr0x0000BD[] = {P0753,P0758,P1706,P0748,P0743,P0731,P0732,P0733};
    
    prog_char P0734[] PROGMEM = "P0734";
    prog_char P1707[] PROGMEM = "P1707";
    prog_char P1595[] PROGMEM = "P1595";
    prog_char P1596[] PROGMEM = "P1596";
    prog_char P0135[] PROGMEM = "P0135";
    prog_char P0141[] PROGMEM = "P0141";
    prog_char P1593[] PROGMEM = "P1593";
    prog_char P1594[] PROGMEM = "P1594";
    
    //0x0000BE and temp 0x00009E  
    //PROGMEM const char *addr0x0000BE[] = {P0734,P1707,P1595,P1596,P0135,P0141,P1593,P1594};
    
    prog_char P0133[] PROGMEM = "P0133";
    prog_char P0130[] PROGMEM = "P0130";
    prog_char P0139[] PROGMEM = "P0139";
    prog_char P0136[] PROGMEM = "P0136";
    prog_char P1152[] PROGMEM = "P1152";
    prog_char P1153[] PROGMEM = "P1153";
    prog_char P0174[] PROGMEM = "P0174";
    prog_char P0175[] PROGMEM = "P0175";
    
    //0x0000BF and temp 0x00009F 
    //PROGMEM const char *addr0x0000BF[] = {P0133,P0130,P0139,P0136,P1152,P1153,P0174,P0175};
    
    prog_char P0420[] PROGMEM = "P0420";
    prog_char P0442[] PROGMEM = "P0442";
    prog_char P0170[] PROGMEM = "P0170";
    prog_char P0456[] PROGMEM = "P0456";
    prog_char P0400[] PROGMEM = "P0400";
    prog_char P1230[] PROGMEM = "P1230";
    prog_char P0171[] PROGMEM = "P0171";
    prog_char P0172[] PROGMEM = "P0172";
    
    //0x0000C0 and temp 0x0000A0  
    //PROGMEM const char *addr0x0000C0[] = {P0420,P0442,P0170,P0456,P0400,P1230,P0171,P0172};
    
    prog_char P0301[] PROGMEM = "P0301";
    prog_char P0302[] PROGMEM = "P0302";
    prog_char P0303[] PROGMEM = "P0303";
    prog_char P0304[] PROGMEM = "P0304";
    prog_char P0305[] PROGMEM = "P0305";
    prog_char P0306[] PROGMEM = "P0306";
    prog_char P1301[] PROGMEM = "P1301";
    prog_char P0457[] PROGMEM = "P0457";
    
    //0x0000C1 and temp 0x0000A1
    //PROGMEM const char *addr0x0000C1[] = {P0301,P0302,P0303,P0304,P0305,P0306,P1301,P0457};
    
    prog_char P0000[] PROGMEM = "P0000";
    prog_char P1235[] PROGMEM = "P1235";
    prog_char P1236[] PROGMEM = "P1236";
    prog_char P1597[] PROGMEM = "P1597";
    prog_char P1598[] PROGMEM = "P1598";
    prog_char P0034[] PROGMEM = "P0034";
    prog_char P0035[] PROGMEM = "P0035";
    
    //0x0000C2 and temp 0x0000A2
    //PROGMEM const char *addr0x0000C2[] = {P0000,P0000,P1235,P1236,P1597,P1598,P0034,P0035};
    
    prog_char P0137[] PROGMEM = "P0137";
    prog_char P1134[] PROGMEM = "P1134";
    prog_char P0131[] PROGMEM = "P0131";
    prog_char P0151[] PROGMEM = "P0151";
    prog_char P0132[] PROGMEM = "P0132";
    prog_char P0152[] PROGMEM = "P0152";
    prog_char P0138[] PROGMEM = "P0138";
    prog_char P0153[] PROGMEM = "P0153";
    David - '05 WRX

  9. #8
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    code, cont. 3

    Code:
    //0x0000C3 and temp 0x0000A3
    //PROGMEM const char *addr0x0000C3[] = {P0137,P1134,P0131,P0151,P0132,P0152,P0138,P0153};
    
    prog_char P0112[] PROGMEM = "P0112";
    prog_char P0113[] PROGMEM = "P0113";
    prog_char P0111[] PROGMEM = "P0111";
    prog_char P1546[] PROGMEM = "P1546";
    prog_char P0038[] PROGMEM = "P0038";
    prog_char P0032[] PROGMEM = "P0032";
    prog_char P0037[] PROGMEM = "P0037";
    prog_char P0031[] PROGMEM = "P0031";
    
    //0x0000C4 and temp 0x0000A4
    //PROGMEM const char *addr0x0000C4[] = {P0112,P0113,P0111,P1546,P0038,P0032,P0037,P0031};
    
    prog_char P1110[] PROGMEM = "P1110";
    prog_char P1111[] PROGMEM = "P1111";
    prog_char P1112[] PROGMEM = "P1112";
    //prog_char P0106[] PROGMEM = "P0106";
    //prog_char P0107[] PROGMEM = "P0107";
    //prog_char P0108[] PROGMEM = "P0108";
    prog_char P1545[] PROGMEM = "P1545";
    prog_char P1146[] PROGMEM = "P1146";
    
    //0x0000C5 and temp 0x0000A5
    //PROGMEM const char *addr0x0000C5[] = {P1110,P1111,P1112,P0106,P0107,P0108,P1545,P1146};
    
    prog_char P1139[] PROGMEM = "P1139";
    prog_char P1140[] PROGMEM = "P1140";
    prog_char P1711[] PROGMEM = "P1711";
    prog_char P1712[] PROGMEM = "P1712";
    prog_char P0715[] PROGMEM = "P0715";
    prog_char P1703[] PROGMEM = "P1703";
    prog_char P0785[] PROGMEM = "P0785";
    prog_char P0778[] PROGMEM = "P0778";
    
    //0x0000C6 and temp 0x0000A6
    //PROGMEM const char *addr0x0000C6[] = {P1139,P1140,P1711,P1712,P0715,P1703,P0785,P0778};
    
    prog_char P1130[] PROGMEM = "P1130";
    prog_char P1135[] PROGMEM = "P1135";
    prog_char P1131[] PROGMEM = "P1131";
    prog_char P1136[] PROGMEM = "P1136";
    prog_char P1154[] PROGMEM = "P1154";
    prog_char P1155[] PROGMEM = "P1155";
    prog_char P0052[] PROGMEM = "P0052";
    prog_char P0051[] PROGMEM = "P0051";
    
    //0x0000C7 and temp 0x0000A7
    //PROGMEM const char *addr0x0000C7[] = {P1130,P1135,P1131,P1136,P1154,P1155,P0052,P0051};
    
    prog_char P0128[] PROGMEM = "P0128";
    prog_char P1491[] PROGMEM = "P1491";
    prog_char P0066[] PROGMEM = "P0066";
    prog_char P0067[] PROGMEM = "P0067";
    prog_char P0065[] PROGMEM = "P0065";
    //prog_char P0130[] PROGMEM = "P0130";
    prog_char P1137[] PROGMEM = "P1137";
    
    //0x0000C8 and temp 0x0000A8
    //PROGMEM const char *addr0x0000C8[] = {P0128,P1491,P0066,P0067,P0065,P0130,P1137,P1137};
    
    prog_char P1248[] PROGMEM = "P1248";
    prog_char P1249[] PROGMEM = "P1249";
    prog_char P1250[] PROGMEM = "P1250";
    prog_char P1560[] PROGMEM = "P1560";
    prog_char P0192[] PROGMEM = "P0192";
    prog_char P0193[] PROGMEM = "P0193";
    prog_char P0562[] PROGMEM = "P0562";
    prog_char P0563[] PROGMEM = "P0563";
    
    //0x0000C9 and temp 0x0000A9
    //PROGMEM const char *addr0x0000C9[] = {P1248,P1249,P1250,P1560,P0192,P0193,P0562,P0563};
    
    prog_char P0245[] PROGMEM = "P0245";
    prog_char P0246[] PROGMEM = "P0246";
    prog_char P1244[] PROGMEM = "P1244";
    prog_char P0244[] PROGMEM = "P0244";
    prog_char P1245[] PROGMEM = "P1245";
    prog_char P0249[] PROGMEM = "P0249";
    prog_char P0250[] PROGMEM = "P0250";
    prog_char P1247[] PROGMEM = "P1247";
    
    //0x0000CA and temp 0x0000AA
    //PROGMEM const char *addr0x0000CA[] = {P0245,P0246,P1244,P0244,P1245,P0249,P0250,P1247};
    
    prog_char P1577[] PROGMEM = "P1577";
    prog_char P1576[] PROGMEM = "P1576";
    prog_char P0513[] PROGMEM = "P0513";
    prog_char P1574[] PROGMEM = "P1574";
    prog_char P1578[] PROGMEM = "P1578";
    prog_char P1572[] PROGMEM = "P1572";
    prog_char P1571[] PROGMEM = "P1571";
    prog_char P1570[] PROGMEM = "P1570";
    
    //0x0000CB and temp 0x0000AB
    //PROGMEM const char *addr0x0000CB[] = {P1577,P1576,P0513,P1574,P1578,P1572,P1571,P1570};
    
    prog_char P1095[] PROGMEM = "P1095";
    prog_char P1097[] PROGMEM = "P1097";
    prog_char P1094[] PROGMEM = "P1094";
    prog_char P1096[] PROGMEM = "P1096";
    prog_char P0261[] PROGMEM = "P0261";
    prog_char P0264[] PROGMEM = "P0264";
    prog_char P0267[] PROGMEM = "P0267";
    prog_char P0270[] PROGMEM = "P0270";
    
    //0x0000CC and temp 0x0000AC
    //PROGMEM const char *addr0x0000CC[] = {P1095,P1097,P1094,P1096,P0261,P0264,P0267,P0270};
    
    prog_char P0545[] PROGMEM = "P0545";
    prog_char P0546[] PROGMEM = "P0546";
    prog_char P1312[] PROGMEM = "P1312";
    prog_char P1544[] PROGMEM = "P1544";
    prog_char P1306[] PROGMEM = "P1306";
    prog_char P1308[] PROGMEM = "P1308";
    prog_char P1307[] PROGMEM = "P1307";
    prog_char P1309[] PROGMEM = "P1309";
    
    //0x0000CD and temp 0x0000AD
    //PROGMEM const char *addr0x0000CD[] = {P0545,P0546,P1312,P1544,P1306,P1308,P1307,P1309};
    
    prog_char P1719[] PROGMEM = "P1719";
    prog_char P1242[] PROGMEM = "P1242";
    prog_char P1241[] PROGMEM = "P1241";
    prog_char P1199[] PROGMEM = "P1199";
    prog_char P1086[] PROGMEM = "P1086";
    prog_char P1087[] PROGMEM = "P1087";
    prog_char P1088[] PROGMEM = "P1088";
    prog_char P1089[] PROGMEM = "P1089";
    
    //0x0000F4 and temp 0x0000F0
    //PROGMEM const char *addr0x0000F4[] = {P1719,P1242,P1241,P1199,P1086,P1087,P1088,P1089};
    
    prog_char P0801[] PROGMEM = "P0801";
    prog_char P0768[] PROGMEM = "P0768";
    prog_char P0763[] PROGMEM = "P0763";
    prog_char P0736[] PROGMEM = "P0736";
    prog_char P0724[] PROGMEM = "P0724";
    prog_char P0719[] PROGMEM = "P0719";
    prog_char P0713[] PROGMEM = "P0713";
    prog_char P0712[] PROGMEM = "P0712";
    
    //0x0000F5 and temp 0x0000F1
    //PROGMEM const char *addr0x0000F5[] = {P0801,P0768,P0763,P0736,P0724,P0719,P0713,P0712};
    
    prog_char P1817[] PROGMEM = "P1817";
    prog_char P1762[] PROGMEM = "P1762";
    prog_char P1761[] PROGMEM = "P1761";
    prog_char P1760[] PROGMEM = "P1760";
    prog_char P1718[] PROGMEM = "P1718";
    prog_char P1714[] PROGMEM = "P1714";
    prog_char P1709[] PROGMEM = "P1709";
    prog_char P1708[] PROGMEM = "P1708";
    
    //0x0000F6 and temp 0x0000F2
    //PROGMEM const char *addr0x0000F6[] = {P1817,P1762,P1761,P1760,P1718,P1714,P1709,P1708};
    
    prog_char P1600[] PROGMEM = "P1600";
    prog_char P2709[] PROGMEM = "P2709";
    prog_char P0773[] PROGMEM = "P0773";
    prog_char P0735[] PROGMEM = "P0735";
    prog_char P1799[] PROGMEM = "P1799";
    prog_char P1798[] PROGMEM = "P1798";
    prog_char P1314[] PROGMEM = "P1314";
    prog_char P1313[] PROGMEM = "P1313";
    
    //0x0000F7 and temp 0x0000F3
    //PROGMEM const char *addr0x0000F7[] = {P1600,P2709,P0773,P0735,P1799,P1798,P1314,P1313};
    
    prog_char P1710[] PROGMEM = "P1710";
    prog_char P1717[] PROGMEM = "P1717";
    prog_char P1716[] PROGMEM = "P1716";
    prog_char P0771[] PROGMEM = "P0771";
    prog_char P0716[] PROGMEM = "P0716";
    prog_char P0726[] PROGMEM = "P0726";
    //prog_char P0720[] PROGMEM = "P0720";
    prog_char P0722[] PROGMEM = "P0722";
    
    //0x00012B and temp 0x000123
    //PROGMEM const char *addr0x00012B[] = {P1710,P1717,P1716,P0771,P0716,P0726,P0720,P0722};
    
    prog_char P2707[] PROGMEM = "P2707";
    //prog_char P0771[] PROGMEM = "P0771";
    prog_char P0766[] PROGMEM = "P0766";
    prog_char P0761[] PROGMEM = "P0761";
    prog_char P0756[] PROGMEM = "P0756";
    prog_char P0751[] PROGMEM = "P0751";
    prog_char P1769[] PROGMEM = "P1769";
    prog_char P1282[] PROGMEM = "P1282";
    
    //0x00012C and temp 0x000124
    //PROGMEM const char *addr0x00012C[] = {P2707,P0771,P0766,P0761,P0756,P0751,P1769,P1282};
    
    prog_char P1844[] PROGMEM = "P1844";
    prog_char P1843[] PROGMEM = "P1843";
    prog_char P1842[] PROGMEM = "P1842";
    prog_char P1841[] PROGMEM = "P1841";
    prog_char P1840[] PROGMEM = "P1840";
    prog_char P1875[] PROGMEM = "P1875";
    prog_char P0558[] PROGMEM = "P0558";
    prog_char P0559[] PROGMEM = "P0559";
    
    //0x00012D and temp 0x000125
    //PROGMEM const char *addr0x00012D[] = {P1844,P1843,P1842,P1841,P1840,P1875,P0558,P0559};
    
    prog_char P0502[] PROGMEM = "P0502";
    prog_char P0230[] PROGMEM = "P0230";
    prog_char P0565[] PROGMEM = "P0565";
    prog_char P0068[] PROGMEM = "P0068";
    prog_char P0129[] PROGMEM = "P0129";
    prog_char P0519[] PROGMEM = "P0519";
    prog_char P0345[] PROGMEM = "P0345";
    //prog_char P0101[] PROGMEM = "P0101";
    
    //0x00012E and temp 0x000126
    //PROGMEM const char *addr0x00012E[] = {P0502,P0230,P0565,P0068,P0129,P0519,P0345,P0101};
    
    prog_char P0154[] PROGMEM = "P0154";
    prog_char P0134[] PROGMEM = "P0134";
    prog_char P0150[] PROGMEM = "P0150";
    //prog_char P0130[] PROGMEM = "P0130";
    prog_char P0050[] PROGMEM = "P0050";
    prog_char P0030[] PROGMEM = "P0030";
    prog_char P0501[] PROGMEM = "P0501";
    prog_char P0503[] PROGMEM = "P0503";
    
    //0x00012F and temp 0x000127
    //PROGMEM const char *addr0x00012F[] = {P0154,P0134,P0150,P0130,P0050,P0030,P0501,P0503};
    
    prog_char P0142[] PROGMEM = "P0142";
    prog_char P0145[] PROGMEM = "P0145";
    prog_char P0156[] PROGMEM = "P0156";
    prog_char P0159[] PROGMEM = "P0159";
    prog_char P0162[] PROGMEM = "P0162";
    prog_char P0165[] PROGMEM = "P0165";
    prog_char P0043[] PROGMEM = "P0043";
    prog_char P0044[] PROGMEM = "P0044";
    
    //0x000130 and temp 0x000128
    //PROGMEM const char *addr0x000130[] = {P0142,P0145,P0156,P0159,P0162,P0165,P0043,P0044};
    
    prog_char P0057[] PROGMEM = "P0057";
    prog_char P0058[] PROGMEM = "P0058";
    prog_char P0063[] PROGMEM = "P0063";
    prog_char P0064[] PROGMEM = "P0064";
    prog_char P0157[] PROGMEM = "P0157";
    prog_char P0158[] PROGMEM = "P0158";
    //prog_char P0143[] PROGMEM = "P0143";
    //prog_char P0144[] PROGMEM = "P0144";
    
    //0x000131 and temp 0x000129
    //PROGMEM const char *addr0x000131[] = {P0057,P0058,P0063,P0064,P0157,P0158,P0143,P0144};
    David - '05 WRX

  10. #9
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    code, cont. 4

    Code:
    prog_char P2109[] PROGMEM = "P2109";
    prog_char P1759[] PROGMEM = "P1759";
    prog_char P1873[] PROGMEM = "P1873";
    prog_char P1872[] PROGMEM = "P1872";
    prog_char P1871[] PROGMEM = "P1871";
    prog_char P1870[] PROGMEM = "P1870";
    prog_char P2125[] PROGMEM = "P2125";
    //prog_char P1700[] PROGMEM = "P1700";
    
    //0x000132 and temp 0x00012A
    //PROGMEM const char *addr0x000132[] = {P2109,P1759,P1873,P1872,P1871,P1870,P2125,P1700};
    
    prog_char P0222[] PROGMEM = "P0222";
    prog_char P0223[] PROGMEM = "P0223";
    prog_char P1160[] PROGMEM = "P1160";
    prog_char P2102[] PROGMEM = "P2102";
    prog_char P2103[] PROGMEM = "P2103";
    prog_char P2101[] PROGMEM = "P2101";
    prog_char P2096[] PROGMEM = "P2096";
    prog_char P0638[] PROGMEM = "P0638";
    
    //0x000155 and temp 0x000150
    //PROGMEM const char *addr0x000155[] = {P0222,P0223,P1160,P2102,P2103,P2101,P2096,P0638};
    
    prog_char P0607[] PROGMEM = "P0607";
    prog_char P2138[] PROGMEM = "P2138";
    prog_char P2127[] PROGMEM = "P2127";
    prog_char P2128[] PROGMEM = "P2128";
    prog_char P2122[] PROGMEM = "P2122";
    prog_char P2123[] PROGMEM = "P2123";
    prog_char P2135[] PROGMEM = "P2135";
    prog_char P2097[] PROGMEM = "P2097";
    
    //0x000156 and temp 0x000151
    //PROGMEM const char *addr0x000156[] = {P0607,P2138,P2127,P2128,P2122,P2123,P2135,P2097};
    
    prog_char P0600[] PROGMEM = "P0600";
    //prog_char P0390[] PROGMEM = "P0390";
    //prog_char P0365[] PROGMEM = "P0365";
    //prog_char P0345[] PROGMEM = "P0345";
    //prog_char P0340[] PROGMEM = "P0340";
    prog_char P0605[] PROGMEM = "P0605";
    prog_char P1521[] PROGMEM = "P1521";
    prog_char P0579[] PROGMEM = "P0579";
    
    //0x000157 and temp 0x000152
    //PROGMEM const char *addr0x000157[] = {P0600,P0390,P0365,P0345,P0340,P0605,P1521,P0579};
    
    prog_char P2095[] PROGMEM = "P2095";
    prog_char P2094[] PROGMEM = "P2094";
    prog_char P2091[] PROGMEM = "P2091";
    prog_char P2090[] PROGMEM = "P2090";
    prog_char P2093[] PROGMEM = "P2093";
    prog_char P2092[] PROGMEM = "P2092";
    prog_char P2089[] PROGMEM = "P2089";
    prog_char P2088[] PROGMEM = "P2088";
    
    //0x000158 and temp 0x000153
    //PROGMEM const char *addr0x000158[] = {P2095,P2094,P2091,P2090,P2093,P2092,P2089,P2088};
    
    prog_char P0197[] PROGMEM = "P0197";
    prog_char P1547[] PROGMEM = "P1547";
    prog_char P1476[] PROGMEM = "P1476";
    prog_char P1475[] PROGMEM = "P1475";
    prog_char P1477[] PROGMEM = "P1477";
    prog_char P2099[] PROGMEM = "P2099";
    prog_char P2098[] PROGMEM = "P2098";
    prog_char P0700[] PROGMEM = "P0700";
    
    //0x000159 and temp 0x000154
    //PROGMEM const char *addr0x000159[] = {P0197,P1547,P1476,P1475,P1477,P2099,P2098,P0700};
    
    prog_char P0028[] PROGMEM = "P0028";
    prog_char P0083[] PROGMEM = "P0083";
    prog_char P0082[] PROGMEM = "P0082";
    prog_char P0026[] PROGMEM = "P0026";
    prog_char P0077[] PROGMEM = "P0077";
    prog_char P0076[] PROGMEM = "P0076";
    prog_char P0196[] PROGMEM = "P0196";
    prog_char P0198[] PROGMEM = "P0198";
    
    //0x000165 and temp 0x000160
    //PROGMEM const char *addr0x000165[] = {P0028,P0083,P0082,P0026,P0077,P0076,P0196,P0198};
    
    prog_char P2100[] PROGMEM = "P2100";
    prog_char P2111[] PROGMEM = "P2111";
    prog_char P2504[] PROGMEM = "P2504";
    prog_char P2503[] PROGMEM = "P2503";
    prog_char P1462[] PROGMEM = "P1462";
    prog_char P1463[] PROGMEM = "P1463";
    prog_char P1028[] PROGMEM = "P1028";
    prog_char P1026[] PROGMEM = "P1026";
    
    //0x000166 and temp 0x000161
    //PROGMEM const char *addr0x000166[] = {P2100,P2111,P2504,P2503,P1462,P1463,P1028,P1026};
    
    prog_char P0958[] PROGMEM = "P0958";
    prog_char P0957[] PROGMEM = "P0957";
    prog_char P0955[] PROGMEM = "P0955";
    prog_char P0883[] PROGMEM = "P0883";
    prog_char P0882[] PROGMEM = "P0882";
    prog_char P0880[] PROGMEM = "P0880";
    prog_char P0817[] PROGMEM = "P0817";
    prog_char P1601[] PROGMEM = "P1601";
    
    //0x000167 and temp 0x000162
    //PROGMEM const char *addr0x000167[] = {P0958,P0957,P0955,P0883,P0882,P0880,P0817,P1601};
    
    prog_char P2004[] PROGMEM = "P2004";
    prog_char P2006[] PROGMEM = "P2006";
    prog_char P2005[] PROGMEM = "P2005";
    prog_char P2007[] PROGMEM = "P2007";
    prog_char P2227[] PROGMEM = "P2227";
    prog_char P0126[] PROGMEM = "P0126";
    prog_char P2229[] PROGMEM = "P2229";
    prog_char P2228[] PROGMEM = "P2228";
    
    //0x000168 and temp 0x000163
    //PROGMEM const char *addr0x000168[] = {P2004,P2006,P2005,P2007,P2227,P0126,P2229,P2228};
    
    prog_char P2016[] PROGMEM = "P2016";
    prog_char P2017[] PROGMEM = "P2017";
    prog_char P2021[] PROGMEM = "P2021";
    prog_char P2022[] PROGMEM = "P2022";
    prog_char P2009[] PROGMEM = "P2009";
    prog_char P2012[] PROGMEM = "P2012";
    prog_char P2008[] PROGMEM = "P2008";
    prog_char P2011[] PROGMEM = "P2011";
    
    //0x000169 and temp 0x000164
    //PROGMEM const char *addr0x000169[] = {P2016,P2017,P2021,P2022,P2009,P2012,P2008,P2011};
    
    //These arrays line up with the address calls to the ECU
    PROGMEM const char *DTCset1[][8] = {{P0335,unkn,P0336,P0341,P0340,unkn,P0604,P0601},
                                      {P0102,P0103,P1141,P0101,P0500,P1540,P0332,P0333}, 
                                      {P0325,P0330,P0327,P0328,P0122,P0123,P1142,P0121},
                                      {P0117,P0118,P0464,P0125,P0462,P0463,P0461,P1442},
                                      {P0107,P0108,P0143,P0144,P0106,P0350,P1518,P0512}, 
                                      {P0452,P0453,unkn,P0451,P1237,P1238,P1239,P1240}, 
                                      {P1590,P1591,P1592,P0851,P0182,P0183,P0181,P0852}, 
                                      {P1510,P1511,P1512,P1513,P1514,P1515,P1516,P1517},
                                      {P1492,P1493,P1494,P1495,P1496,P1497,P1498,P1499}, 
                                      {P1102,P1122,P1446,P1447,P1090,P1091,P1092,P1093}, 
                                      {P0508,P0509,P1507,P0506,P0507,P1698,P1699,P1448},
                                      {P0444,P0445,P0691,P0692,P0480,P1480,P0483,P0864}, 
                                      {P0365,P0390,P0011,P0021,P1400,P1420,P0458,P0459}, 
                                      {P0865,P0866,P1443,P1559,P0661,P0662,P0447,P0448}, 
                                      {P0720,P0725,P1700,P0710,P0705,P1701,P0703,P0741}, 
                                      {P0753,P0758,P1706,P0748,P0743,P0731,P0732,P0733}, 
                                      {P0734,P1707,P1595,P1596,P0135,P0141,P1593,P1594}, 
                                      {P0133,P0130,P0139,P0136,P1152,P1153,P0174,P0175}, 
                                      {P0420,P0442,P0170,P0456,P0400,P1230,P0171,P0172}, 
                                      {P0301,P0302,P0303,P0304,P0305,P0306,P1301,P0457}, 
                                      {P0000,P0000,P1235,P1236,P1597,P1598,P0034,P0035}, 
                                      {P0137,P1134,P0131,P0151,P0132,P0152,P0138,P0153}, 
                                      {P0112,P0113,P0111,P1546,P0038,P0032,P0037,P0031}, 
                                      {P1110,P1111,P1112,P0106,P0107,P0108,P1545,P1146}, 
                                      {P1139,P1140,P1711,P1712,P0715,P1703,P0785,P0778}, 
                                      {P1130,P1135,P1131,P1136,P1154,P1155,P0052,P0051}, 
                                      {P0128,P1491,P0066,P0067,P0065,P0130,P1137,P1137}, 
                                      {P1248,P1249,P1250,P1560,P0192,P0193,P0562,P0563}, 
                                      {P0245,P0246,P1244,P0244,P1245,P0249,P0250,P1247}, 
                                      {P1577,P1576,P0513,P1574,P1578,P1572,P1571,P1570}, 
                                      {P1095,P1097,P1094,P1096,P0261,P0264,P0267,P0270}, 
                                      {P0545,P0546,P1312,P1544,P1306,P1308,P1307,P1309}};
                                      
    PROGMEM const char *DTCset2[][8] = {{P1719,P1242,P1241,P1199,P1086,P1087,P1088,P1089},
                                      {P0801,P0768,P0763,P0736,P0724,P0719,P0713,P0712},
                                      {P1817,P1762,P1761,P1760,P1718,P1714,P1709,P1708},
                                      {P1600,P2709,P0773,P0735,P1799,P1798,P1314,P1313},
                                      {P1710,P1717,P1716,P0771,P0716,P0726,P0720,P0722},
                                      {P2707,P0771,P0766,P0761,P0756,P0751,P1769,P1282},
                                      {P1844,P1843,P1842,P1841,P1840,P1875,P0558,P0559},
                                      {P0502,P0230,P0565,P0068,P0129,P0519,P0345,P0101},
                                      {P0154,P0134,P0150,P0130,P0050,P0030,P0501,P0503},
                                      {P0142,P0145,P0156,P0159,P0162,P0165,P0043,P0044},
                                      {P0057,P0058,P0063,P0064,P0157,P0158,P0143,P0144},
                                      {P2109,P1759,P1873,P1872,P1871,P1870,P2125,P1700},
                                      {P0222,P0223,P1160,P2102,P2103,P2101,P2096,P0638},
                                      {P0607,P2138,P2127,P2128,P2122,P2123,P2135,P2097},
                                      {P0600,P0390,P0365,P0345,P0340,P0605,P1521,P0579},
                                      {P2095,P2094,P2091,P2090,P2093,P2092,P2089,P2088},
                                      {P0197,P1547,P1476,P1475,P1477,P2099,P2098,P0700},
                                      {P0028,P0083,P0082,P0026,P0077,P0076,P0196,P0198},
                                      {P2100,P2111,P2504,P2503,P1462,P1463,P1028,P1026},
                                      {P0958,P0957,P0955,P0883,P0882,P0880,P0817,P1601},
                                      {P2004,P2006,P2005,P2007,P2227,P0126,P2229,P2228},
                                      {P2016,P2017,P2021,P2022,P2009,P2012,P2008,P2011}};
    David - '05 WRX

  11. #10
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249

    Troubleshooting the circuit

    I'm surprise that I've received no response for this post; I'm proud to have been able to come even this far on this project.

    That's not to say that there are not better implementations of a similar idea: RomRaider ‚€Ę View topic - Arduino Based SSM Gauge

    Anyhow, I was looking at the cables in the OBD II port of my car, as well as the circuit in the Vag Com cable to see if I could understand why the cable allowed my circuit to communicate with the car.



    I noticed that not all of the cables are hooked up. In fact, although I had previously realized that the vag com cable could communicate with pin 7 or pin 15 (they seemed to send and receive the same bytes), the OBD port in the car does not have a connection with pin 15!. By looking at the two circuits, I can conclude that the power, ground and pin 7 are all that are involved in the communication.

    This means that I have narrowed down my sources of error:
    1) Perhaps my V+ in the clock pod is not correct, or maybe the pullup should be at the OBD port (the vag com cable effectively does this)
    2) perhaps my ground at the cigarette lighter is not the same ground as the ECU/OBD comms (not much of a chance of this, but the cable provides a common ground between them)
    3) There is still a chance that the comparator circuit is active in the communication.

    I can test these ideas with a multimeter. I will report back.
    David - '05 WRX

  12. #11
    Registered User gregroot198521's Avatar
    Join Date
    Feb 2011
    Location
    El Paso, TX
    Posts
    776
    Hmm, dig this, I'll have to do a real read up again later though.
    Hawkeye Alliance #1050
    Build Thread
    http://i1108.photobucket.com/albums/...ps665d9b9d.jpg
    Always dirty, never scurred......

  13. #12
    Registered User Obeisance's Avatar
    Join Date
    Apr 2012
    Location
    Ann Arbor
    Posts
    249
    Alright, I finally got around to checking the OBD II port with a multimeter and here's what I found:

    V+ (pin 16) is 12.XX V=battery voltage above ground (pin 4/5) and pin 4/5 matches chassis ground (why wouldn't it). No big surprises here. I measured Pin 7 vs 4/5 and got 6.XXV, and vs pin 16 and got -5.XX V, but I still had the arduino signaling turned on. When adruino signaling is disabled, I get -0.23 V vs pin 16 and 11.88 V vs gnd. (this means that the signaling is reaching the OBD port just fine, I believe)

    Placing a 1 kOhm or 10 kOhm resistor as a jump (pull-up) between 4 and 7 or 16 and 7 does not enable the communication to pass through, so it appears that the comparator is active rather than a voltage drop over the signal line causing the failure in communication.

    Also, I double checked the VAG com cable, and the only chip in it which is powered via OBD is the comparator (the FTDI chip is powered via USB). Ugh.
    David - '05 WRX

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •