Sunday, March 12. 2017Nissan Leaf CAN Bus Man In The MiddleI wrote a man in the middle for the leaf battery communication. It uses can4python and Kayak's kcd format to describe the signals. It probably only works on Linux. Source code is here https://carrott.org/git/leaf-can-utils.git It decodes all the messages received on one interface (from the battery) into signals, lets me change their values, and then re-encodes them back into the can bus format, recalculates the new checksum when necessary and sends them out the other interface (to the car). It displays each signal and the received and sent signals: Hexadecimal Decimal In Out In Out 1db Checksum: 007e 007e 126 126 1db Counter: 0002 0002 2 2 1dc Checksum: 005d 005d 93 93 55b Checksum: 007e 00dc 126 220 5bc 2_2: 0002 0002 2 2 Capacity Bars: 000a 000a 10 10 Li-ion battery available charge signal (%): 0040 0040 64 64 Li-ion battery capacity signal (GID): 0074 0074 116 116 Li-ion battery current signal: -0001 -0001 -1 -1 Li-ion battery gradual capacity loss signal?: 0068 0068 104 104 Li-ion battery voltage signal: 017f 017f 383 383 Temperature: 007e 007e 126 126 Wheel Speed: 0000 0000 0 0 _1db 1_2: 00 00 0 0 _1db 3_2: 2a 2a 42 42 _1db 4: 00 00 0 0 _1db 5: 00 00 0 0 _1dc 0: 6e 6e 110 110 _1dc 1: 04 04 4 4 _1dc 2: df df 223 223 _1dc 3: fd fd 253 253 _1dc 4: 04 04 4 4 _1dc 5: d8 d8 216 216 _1dc 6: c6 c6 198 198 _55b 1_2: 00 00 0 0 _55b 2: aa aa 170 170 _55b 3: 00 00 0 0 _55b 4: e0 e0 224 224 _55b 5: 00 00 0 0 _55b 6: 10 10 16 16 _5bc 1_2: 03 03 3 3 _5bc 3: 3f 3f 63 63 _5bc 4_1: 09 09 9 9 _5bc 5: 05 05 5 5 _5bc 6: 40 40 64 64 _5bc 7: 5a 5a 90 90 _5bc Mux_02: 07 07 7 7 _5c0 3: 00 00 0 0 _5c0 6: 00 00 0 0 _5c0 7: 02 02 2 2 _5c0 Mux_1_40: 7e 7e 126 126 _5c0 Mux_1_80: 7e 7e 126 126 _5c0 Mux_1_c0: 7e 7e 126 126 _5c0 Mux_2_80: 7e 7e 126 126 _5c0 Mux_2_c0: 7e 7e 126 126 _5c0 Mux_5_40: 6c 6c 108 108 _5c0 Mux_5_80: d0 d0 208 208 _5c0 Mux_5_c0: c4 c4 196 196 Yesterday I spent some time testing it on a Gen 1 leaf at Blue Cars We cut the can bus wires inside the battery box, just after they go through the water proof connector to the outside and connected about 1 metre of thin figure 8 wire to each side of the cut. This let us access the bus on the car and the bus on the battery while the battery was plugged in under the car. It's possible to get enough slack in the internal battery loom to feed the connector all the way through the machined hole and make room for some extra wires to pass through. This is obviously only suitable for testing as the battery is no longer waterproof, but let us fasten the lid onto the battery before sliding it back under the car and lifting it up to meet the cables below the car. With the two pairs connected together, the car behaved normally, going into ready and spinning the wheels. The BMS module terminates the bus so we connected a termination resistor to the car side of the cut and used termination on the CAN interface talking to the battery. We plugged the other end of the man in the middle to the OBD2 port and didn't use termination. The MitM just worked! The car is very tolerant of errors on the CAN bus. You can stop the battery messages and it goes into turtle mode and all the battery info disappears off the instrument cluster. When you re-start the battery messages it goes back to normal mode and the battery info reappears. Start-up is quite critical, if you don't let the battery send it's start up messages the car doesn't go into ready mode. The car never shut down or went into a permanent turtle mode while I was messing with data on the bus -- it always went back to normal mode if I restored the unmodified message flow from the BMS. I modified the data in nearly every field to see what would happen. The car will go into ready and turn the wheels even when it cannot send messages to the battery. This means the startup sequence doesn't involve a car to battery handshake, even if the car is expecting some startup messages from the battery within a time window. The "check engine" light comes on and it does record some DTCs:
My MitM only works in one direction (from the battery to the car) and it turns out my CAN bus setup wouldn't let two programs play together, so when I started a CAN repeater (candump -b) to copy data from the car to the battery I got corrupted frames and no buffer space errors. I'm going to make the MitM work in both directions to resolve this. If you play a different car's battery messages into this car, it does not go into ready. I didn't spend much time on this and I didn't write code to start the BMS messages at the right time, I just started playing the recording of a running BMS and switched the car on. One experiment that I should have tried was to start the car with it's real battery and then switch to messages recorded from a different car. There are some new DTCs when you try to start a the car while playing messages recorded from another car including
The next experiment is to swap in a BMS module from another car. I figured out some more of the BMS protocol by messing with the data and seeing how the car reacted. The Fuel Gauge display on the instrument cluster is powered by the GIDs signal (the first 10 bits of 0x5BC), not the state of charge signal (first 10 bits of 0x55B). I guess it knows how many GIDS is "full" because the battery will have fewer gids and still read full as it ages. 0x5BC bits 36-39 (ie the high nibble of the 5th byte) somehow effects the Fuel Gauge, lower numbers mean more bars, all other things being the same. Maybe this is used to calculate how many GIDs each bar is worth? I haven't explored this. The battery capacity gauge (the bars outside the fuel gauge) is controlled by a muxed field, when 0x5BC bits 32-35 (ie the low nibble of the 5th byte) is 0x3, 0x5BC bits 16-19 (ie the low nibble of the 3rd byte) contains the capacity bars. I haven't yet used the mux field support in the kcd format to express this -- can4python doesn't support it so I had to hand code it. The cluster does not remember the capacity -- changing this value directly manipulates the number of bars displayed, the value on the can bus is literally the number of bars (0x0 -> no bars, 0xC -> 12 bars). The indicated temperature on the instrument cluster is controlled by another muxed field, when 0x5C0 is 0x40, the indicated temperature is controlled by the 3rd byte of 0x5C0. This mux has 3 values, on this car all 3 are similar in the 3rd byte, but only the when the mux is 0x40 does the 3rd byte control the temperature in the instrument cluster. Many thanks to Carl at Blue Cars for letting me torture his car and Bill & Ed for assisting. Trackbacks
Trackback specific URI for this entry
No Trackbacks
Comments
Display comments as
(Linear | Threaded)
No comments
The author does not allow comments to this entry
|
Errorserendipity error: could not include @serendipity_html_nugget_plugin:185f6f376b1b08b446a92b05bfcdc7a1 - exiting.
Errorserendipity error: could not include @serendipity_syndication_plugin:3350747ad57cf5d3bf3643dd4bfb538f - exiting.
Errorserendipity error: could not include @serendipity_archives_plugin:7015fd6c22523f7c6f1ff00a3ba7e879 - exiting.
|