Got a 2016 ST a couple months ago, and have been driving it back and forth to work. The only thing I have done so far is put it on snow tires. It’s a very fun car, but the interior does leave something to be desired. Maybe it’s just my paranoia from driving Subarus, but I can’t stand not having things like water temp on my dash. So I think I will tackle things like that first. From there I might try to do some autocross/rallycross, but that would be a new form of racing to me. So I’m sure I’ll need to address other aspects of the car eventually.
My first thought and probably yours too was just use one of those ELM OBD dongles and an Android app. I have used that in the past but I’ve never seen anything I can’t build myself. Also, I don’t want to be locked into their code and limitations. For example I don’t think you can code up something like gear position in those apps or really go crazy with the theming. Gonna need some help once I get to the theming part. I’m going to be sharing my code in the hopes that people will work along with me and contribute.
Here are the parameters I’m interested in right now:
That’s all I can think of right now before actually getting any track time and finding out what else I’m forgetting. Let me know if you have been looking for anything. It would be fun to do some reverse engineering on non standard IDs.
To start I’m gonna put all of this on a tablet or phone, then I hope to eventually integrate it a bit more permanently with dedicated screens and gauges.
First I’m gonna get my code working using a computer, USB to Macchina M2. Then I will port everything to a phone/webapp and smaller dongle or maybe tap the lines directly to leave the obd port open.
Luckily I’m not on my own. There is plenty of code laying around I can use.
I started with this code:
It seemed to be working for other people but not the Fiesta. So I took SavvyCAN and the M2 again and spied on a diagnostic dongle that I did know was working.
Here was my general reverse eingeering process:
Turns out it was just the length of the message the Fiesta was expecting. A friend who understands CAN better than me spotted this difference in the logs. With a quick change from 29 to 11 bit messages and I was finally getting data.
I added this: frame.extended = 0;
Now this code should work for the fiesta to print out whatever PIDs you request:
Project build Files Summary:
I will add further updates in future posts, but I will try to keep this section updated with my latest files and links for anyone looking to recreate this project or work along with me.
2/7/2020:
Macchina M2 - (engineering tool that I will eventually replace with something less expensive)
SavvyCAN - (great tool with a bit of a learning curve, Getting M2 set up with savvycan doc here, SavvyCAN feature documentation here)
OBD2 code (directly above)
Next:
I'm going to try calculating Boost, I also have an idea for a quick way to display this data on an old cell phone over wifi.
My first thought and probably yours too was just use one of those ELM OBD dongles and an Android app. I have used that in the past but I’ve never seen anything I can’t build myself. Also, I don’t want to be locked into their code and limitations. For example I don’t think you can code up something like gear position in those apps or really go crazy with the theming. Gonna need some help once I get to the theming part. I’m going to be sharing my code in the hopes that people will work along with me and contribute.
Here are the parameters I’m interested in right now:
- Oil temp/Pressure (standard PID)
- Water temp (standard PID)
- Battery voltage (standard PID)
- Boost (calculated)
- Gear position (found in CAN) - See post below
- Fuel usage (calculated) - I have seen this done a few ways
- I would also like to better display how much traction control is kicking in
That’s all I can think of right now before actually getting any track time and finding out what else I’m forgetting. Let me know if you have been looking for anything. It would be fun to do some reverse engineering on non standard IDs.
To start I’m gonna put all of this on a tablet or phone, then I hope to eventually integrate it a bit more permanently with dedicated screens and gauges.
First I’m gonna get my code working using a computer, USB to Macchina M2. Then I will port everything to a phone/webapp and smaller dongle or maybe tap the lines directly to leave the obd port open.
Luckily I’m not on my own. There is plenty of code laying around I can use.
I started with this code:
C++:
#include <due_can.h>
uint8_t codes[4] = {5, 0xB, 0xC, 0xD};
int idx = 0;
uint32_t tick = 0;
void sendPIDRequest(uint32_t id, uint8_t PID)
{
CAN_FRAME frame;
frame.id = id;
frame.length = 8;
for (int i = 0; i < 8; i++) frame.data.bytes[i] = 0xAA;
frame.data.bytes[0] = 2; //2 more bytes to follow
frame.data.bytes[1] = 1;
frame.data.bytes[2] = PID;
Can0.sendFrame(frame);
}
void processPID(CAN_FRAME &frame)
{
int temperature;
float psi;
int RPM;
int MPH;
if (frame.data.bytes[1] != 0x41) return; //not anything we're interested in then
switch (frame.data.bytes[2])
{
case 5:
temperature = frame.data.bytes[3] - 40;
SerialUSB.print("Coolant temperature (C): ");
SerialUSB.println(temperature);
break;
case 0xB:
psi = frame.data.bytes[3] * 0.145038; //kPA to PSI
SerialUSB.print("Manifold abs pressure (psi): ");
SerialUSB.println(psi);
break;
case 0xC:
RPM = ((frame.data.bytes[3] * 256) + frame.data.bytes[4])/4;
SerialUSB.print("Engine RPM: ");
SerialUSB.println(RPM);
break;
case 0xD:
MPH = frame.data.bytes[3] * 0.621371;
SerialUSB.print("Vehicle Speed (MPH): ");
SerialUSB.println(MPH);
break;
}
}
void setup() {
Can0.begin(CAN_BPS_500K);
int filter;
//extended
for (filter = 0; filter < 3; filter++) {
Can0.setRXFilter(filter, 0, 0, false);
Can1.setRXFilter(filter, 0, 0, false);
}
}
void loop() {
CAN_FRAME incoming;
if (Can0.available() > 0) {
Can0.read(incoming);
if (incoming.id > 0x7DF && incoming.id < 0x7F0)
{
processPID(incoming);
}
}
//every second rotate to a new code and send it. Hopefully something replies
if (millis() > (tick + 1000) )
{
tick = millis();
sendPIDRequest(0x7DF, codes[idx]);
idx = (idx + 1) % 4;
SerialUSB.println(".");
}
}
Here was my general reverse eingeering process:
1 start logging CAN data with SavvyCAN
2 start the car
3 wait for new IDs to stop showing up
4 filter out those IDs
5 Plug in other dongle (using a splitter cable)
6 See what new IDs were added
I also made logs of each device, mine and the working example.Turns out it was just the length of the message the Fiesta was expecting. A friend who understands CAN better than me spotted this difference in the logs. With a quick change from 29 to 11 bit messages and I was finally getting data.
I added this: frame.extended = 0;
Now this code should work for the fiesta to print out whatever PIDs you request:
C++:
#include <due_can.h>
uint8_t codes[4] = {5, 0xB, 0xC, 0xD};
int idx = 0;
uint32_t tick = 0;
void sendPIDRequest(uint32_t id, uint8_t PID)
{
CAN_FRAME frame;
frame.id = id;
frame.extended = 0;
frame.length = 8;
for (int i = 0; i < 8; i++) frame.data.bytes[i] = 0xAA;
frame.data.bytes[0] = 2; //2 more bytes to follow
frame.data.bytes[1] = 1;
frame.data.bytes[2] = PID;
Can0.sendFrame(frame);
}
void processPID(CAN_FRAME &frame)
{
int temperature;
float psi;
int RPM;
int MPH;
if (frame.data.bytes[1] != 0x41) return; //not anything we're interested in then
switch (frame.data.bytes[2])
{
case 5:
temperature = frame.data.bytes[3] - 40;
SerialUSB.print("Coolant temperature (C): ");
SerialUSB.println(temperature);
break;
case 0xB:
psi = frame.data.bytes[3] * 0.145038; //kPA to PSI
SerialUSB.print("Manifold abs pressure (psi): ");
SerialUSB.println(psi);
break;
case 0xC:
RPM = ((frame.data.bytes[3] * 256) + frame.data.bytes[4])/4;
SerialUSB.print("Engine RPM: ");
SerialUSB.println(RPM);
break;
case 0xD:
MPH = frame.data.bytes[3] * 0.621371;
SerialUSB.print("Vehicle Speed (MPH): ");
SerialUSB.println(MPH);
break;
}
}
void setup() {
Can0.begin(CAN_BPS_500K);
int filter;
//extended
for (filter = 0; filter < 3; filter++) {
Can0.setRXFilter(filter, 0, 0, false);
Can1.setRXFilter(filter, 0, 0, false);
}
}
void loop() {
CAN_FRAME incoming;
if (Can0.available() > 0) {
Can0.read(incoming);
if (incoming.id > 0x7DF && incoming.id < 0x7F0)
{
processPID(incoming);
}
}
//every second rotate to a new code and send it. Hopefully something replies
if (millis() > (tick + 1000) )
{
tick = millis();
sendPIDRequest(0x7DF, codes[idx]);
idx = (idx + 1) % 4;
SerialUSB.println(".");
}
}
Project build Files Summary:
I will add further updates in future posts, but I will try to keep this section updated with my latest files and links for anyone looking to recreate this project or work along with me.
2/7/2020:
Macchina M2 - (engineering tool that I will eventually replace with something less expensive)
SavvyCAN - (great tool with a bit of a learning curve, Getting M2 set up with savvycan doc here, SavvyCAN feature documentation here)
OBD2 code (directly above)
due_can.h (referenced in OBD2 code)
Next:
I'm going to try calculating Boost, I also have an idea for a quick way to display this data on an old cell phone over wifi.
Last edited: