Thursday, October 5, 2017

More CAN filtering and next ideas...

In the last post I mentioned some warnings and errors appearing in the dashboard due to my hacking of message 0x167. Because the CEM now thinks that the engine is running, it validates some other messages coming from the ECM. Today I found some time to tackle the issue - and it took only 2 hours to not only fix the problem but enhance the situation even more :)
I found out that the status of the alternator and probably even some information about the cooling system (not the temperature itself) is sent via message 0x3d3. I replace the content of this message with values from the other S80: 0x24, 0x42, 0x00, 0x04, 0x75, 0x78, 0x76, 0x08 and after clearing the DTC's, the Dashboard is happy - as will be the experts conducting the regular checks for street worthiness. I didn't bother yet to find out exactly which bytes are relevant.
As I was already at it, I thought somewhere the RPM must be hidden too. In my previous hacks, I only focused on the climate controls and error messages in the dash. I never checked the tachometer. So I checked the logs in Excel again to find messages from the ECM which differ between "ignition on" and "engine idle". In "engine idle" they case must fluctuate a bit because the engine speed is never 100% constant. As Murphy's law requires, I started on the wrong side with the high numbered message id's until I hit message 0x12a and saw the needle jump up to 700rpm. Bingo! The engine speed is encoded in the last two bytes - well, actually only the last 13 bits. As byte 7 already had the value 0xe0 with ignition on (in my car), I simply add the two values. So that's what it looks like now (mind that the array starts at [0] - hence [7] is byte 8:

bytes[6] = 0xe0 | (rpm & 0xff00) >> 8;
bytes[7] = rpm & 0xff;

To transport the rpm of the electric motor over to the CAN filter, I use GEVCU's CAN bus which is connected to the car's high-speed bus and send the value in a new message id 0x129. The filter picks up the value when message 0x129 is received. Then, when message 0x12a is received, it injects the value. Works perfectly fine and now I have a working tachometer - well, except that the instrument doesn't display rpm's between 0 and 500 - it stays at 0 and then jumps to 500 - but what the heck, I can live with that.
The code for the filter can be found on github:

Next ideas

As I don't have a clutch anymore, shifting has become a bit tricky. Gears can only be shifted with zero torque and the synchros are used to adjust the motor speed. This shortens the life of the synchros and is also difficult for drivers unfamiliar with the procedure. Even I get into trouble now and then when the GEVCU dash isn't working and I don't find the spot where I'm coasting (zero torque). So the next step is to grab the vehicle's speed from the CAN bus (not via OBD2, too slow) and from the ratio of engine vs. vehicle speed find out in which gear I'm driving. Then I'll add a capacitive switch to the gear shifter and change the code of GEVCU like follows:

  1. When the switch is activated (gear knob touched), the torque is reduced to 0 for 1 sec (or less).
  2. With 0 torque, the driver can switch the gear to "neutral".
  3. Depending on wether the throttle is in "acceleration" or "deceleration" mode, GEVCU will adjust the motor speed within 0.2-0.5sec so it fits the next lower or higher gear.
  4. Torque is again reduced to 0 (or almost 0) so the gear can be inserted.
  5. When the knob/switch is released, normal operation is resumed.

I just made up the timing as I have no experience yet on how long the steps will take. I'll have to experiment with the timing as well as the torque applied to adjust the speed quickly enough but without unnecessarily stressing the hardware.
And of course I won't be entering the speed ratios for the different gears.. the GEVCU has to be able to find the different ratios automatically.

Sunday, October 1, 2017

0x167, byte 5, bit 6

A couple of months ago I found the CAN message on the low-speed CAN bus which would be sent from the CEM (Central Electronic Module) to the CCM (Climate Control Module) if the engine was running. It would enable all the high-power consumers like seat heater, seat ventilator, rear window de-mist. The only caveat was that while I injected the message, the CEM sent the same one about 2-5 per second to switch things off again. I thought about cutting the CAN wires and inserting a filter. But as the SRS (airbag) is also on that bus, I was hesitant - luckily. Because one week ago, I came up with the idea, why not do the same thing between the ECM (Engine Control Module) and the CEM. Instead of faking input signals to make the ECM believe that an engine is running, I could do it at a later stage: "adjust" the CAN signal from the ECM.
So yesterday I dared and started looking for the high-speed CAN wires. I was lucky. I cut the umbilical of the cable tree open - close to the coolant expansion tank. The twisted blue-black (CAN-High) and green-black (CAN-Lo) wires were right on the top - no digging through 30-40 wires. A courageous cut and a Arduino-Due based CAN shield soldered in and I had a filter ready. ECM on bus 1, rest on bus 0. This way it was a piece of cake to find out which messages are coming from the ECM (0x30, 0x125, 0x12a, 0x143, 0x157, 0x167, 0x315, 0x385, 0x392, 0x3d3, 0x4ca) and which are coming from the other devices (at least 23 other messages). This reduced the reverse-engineering efforts dramatically by about 70%. First I suspected it'd be message id 0x30. Usually these low-end numbers are used for basic status information. Wrong! It seems to be the device's ID - which changes when the engine is running - but yet it wasn't the one yet. So, what did I do?
Another friendly S80 MY08 owner, allowed me to grab some logs from his car with ignition on and with engine idling. With these logs, Excel and Collin Kidders SavyCan, I identified which messages contain different data between the two states. Still a lot! So I started replacing the content of messages one message id at a time, first I used the other car's data for 0x30 --> de-mobilizer got activated. Then 0x125 --> DSTC system failure, then 0x12a --> DSTC error and de-mobilizer, and so on and so on. Most of the other messages had no visible effect.
Then once I uploaded a new firmware change to the Arduino, I got partially lucky: I forgot to switch off ignition and during the upload, the CEM obviously lost communication with the ECM and the whole christmas tree lit up: all seat heaters, fans, BLIS (Blind Spot Indicator System) were enabled for a short time. So today, I just pulled the plug of the Arduino - meaning no messages get forwarded anymore. And although many errors appeared on the dashboard, all the desired devices were available to me. Geeee! This looked promising. So assiduously I started filtering out entire messages - again starting with 0x30 and working my way up. With the sixth attempt, I got lucky: 0x167 must be it! Then I added it again but with the contents from the other S80 and the devices still worked. Next step: only replace the contents of the last 4 bytes and leave the first 4 as they come from the ECM: still ok. Then leave the content of byte 5 and 6 unchanged: not working anymore. With the reference data from the other S80 for byte 5 being 0x22 with ignition on and 0x62 with running engine it became clear quickly that it must be bit 6. So now I just do a bytes[4] |= 0x40 to set the bit and Vida now tells me that the ECM's "power state" is no longer "ignition on" but "running". And now instead of just the working seat heater (most important!) and ventilator and de-mist, I also got a running BLIS and the head-lamps swivel again in the direction I steer. Fantastic! :)
There are only 3 issues which need to be resolved now as the engine appears to be running, more signals are verified:
  1. The red "alert" and the battery warning sings light up in the dashboard together with the message that the alternator system has a serious malfunction. The DTC tells me there's a missing message. 
  2. Because I didn't attach a coolant temperature sensor or fake the signal, I get a yellow "warning" sing and a message about an issue in the engine coolant system
  3. The auxiliary brake pressure pump still doesn't come on when braking abruptly. For a real emergency stop, I have to push the brake very hard until ABS kicks in.
  4. Still don't get a RPM reading on the dashboard.
In a daily drive 1. is the most annoying thing. But as the DTC says a message is missing, maybe the ECM just sends one more message containing data from the alternator. Once I find it and inject it, it should go away. Point 2 should be easy to remedy - and even if I can't I could live with it. 
Point 3 is not annoying while driving but it's the most critical in an emergency - especially if other people are driving the car. I don't know what needs to be done to make the BCM (Brake Control Module) switch on the auxiliary pump. Maybe I'll just use the brake pressure which is read in by GEVCU anyway and then send the CAN bus command to turn on/off the auxiliary pump (can grab this from the Vida log as it can be switched on/off from the tool).
Point 4 just needs a bit more fumbling around with the remaining CAN messages. I'm convinced the RPM of the engine is in one of the 11 messages sent from the ECM.

If anyone has information or a good idea on how to resolve these 4 points, I'd appreciate it!