RX8 Project – Part 19, Canbus #4, The Comeback!

Lets be clear before we start – This will not allow you to start a car with a factory ECU with the wrong key or by bypassing the immobiliser. This is to do with making things like engine swaps work fully in the car without the factory ECU connected.

I’m going to apologise right now, there’s quite a lot of background about how I investigated the process of the ECU talking to the immobiliser in this one, if you don’t care and just want the CAN info scroll down a bit. I’ll write a complete update of all the codes when this phase of work is all done.

As some of you are probably aware my RX8 engine swap has been going on some time for a variety of reasons but specifically due to not having cover and so not easily being able to hook the car CANbus up to my computer to do live diagnostics I had hit something of a problem. I couldn’t generate data fast enough to fake all the devices on the bus reliably to test things on my desk away from the car but had no-where undercover to work with it connected to a PC so largely I’d planned to concentrate on organising a garage – something that should have happened more than a year ago now but due to the pandemic and related 2020 problems that not gone as well as hoped!

Anyway a few months ago on trying to find a CAN diagram for the car to aid answering a comment someone posted on here (yes I do try to answer them but I know sometimes it takes a while – I’m hoping to keep a better eye on it this year!) I came across a video from a guy called Dave Blackhurst (this one) which was rather interesting as he apparently had my two main issues from my previous code sorted, specifically the immobiliser system (the thing I want to look at here) and the power steering.

So to see how he was doing it I went to the linked Github and downloaded his Arduino code and on opening it I was largely very familiar code, specifically a whole set of variable declarations for the various dash instruments and a large section of code related to using a boolean variable to set the correct bit in the corresponding CAN packet so individual warning lights can be turned on or off and the speed/RPM etc to all be set easily on the cluster. So this was basically a development of my previous work

Now just to be clear this isn’t a complaint. This is just the first time I’d see my work go full circle and someone else actually develop it further which was quite exciting. If I hadn’t wanted it used and developed I wouldn’t have posted it online! Even better was it gave me a kick to have another go at it and at the very least try this new and improved code which said it fixed all the issues because if true Dave might have just solved my remaining problems!

So back to the immobiliser. I’d never managed to get the immobiliser light to go out despite trying all sorts of combinations of data from the logs I had but after seeing what Dave had done I realised I’d been missing a critical bit of information. The CAN logs I’d previously worked from were predominantly provided but someone else who contacted me via the blog and so were from two other cars and not my own. Additionally you can see in the early blog posts I actually built my own CANbus board several years ago which worked but had some speed issues with all the work it was doing. This was because when I started this project several years ago there was little else available for sensible money so it was the only real option. Long story short the immobiliser relies on a very short data exchange which occurs when the ignition key is first turned on and is never repeated and basically it had just been missed by the loggers that I had data from previously so I may never have figured it out!

Excited at the prospect of this just being a load the code and go I wondered if in the intervening years better hardware was available for this job than my old Arduino Nano based DIY job and there are now various Arduino expansion shields for CAN but to me these were all rather clunky solutions so I started looking at the “Feather” range which has a couple options but again these were a board and a piggback interface which isn’t what I wanted and there’s a new one which is the Adafruid Feather M4 CAN which looked pretty good but doesn’t seem to have ever actually been in stock anywhere so moving on.

Adafruit Feather M4 CAN

Following this I had a realisation – if if was going on the car it really didn’t need an integrated battery. Previously I’d started using Leonardo based modules for projects and these proved very quick for most tasks and have integrated USB meaning data throughput can be faster so I tried to find a Leonardo based CAN module. Eventually I found a company who I’ve used before for various neat modules do basically exactly what I was after for a reasonable price, enter Hobbytronics and their L-CANBUS board.

Leonardo CAN BUS board
Hobbytronics Leonardo Canbus

Looks just the job and even comes with the headers and 9 way connector unsoldered. and the board itself has pads for screw terminals to be soldered in place of the 9 way connector for bare wire connections. This time round I decided I wasn’t going to mess about with screw terminals while testing so I splashed out and bought a £10 OBD2 – 9 Way D-Sub CAN cable off eBay to go with it (unfortunately Hobbytronics were out of stock of the cable). This also had the advantage of including 12V and ground connections which are routed to the board regulator so the module is powered directly off the OBD2 port on the car making testing really easy.

I also decided being powered off the car that rather than risk shorting the module/car it needed a case and since I recently was given what I believe is still the cheapest 3d printer on eBay by a friend who got so annoyed with it he bought one that was actually good, so I designed a 3d printable one :

It’s pretty basic, the holes should be undersize for an M2.5 laptop screw so they basically thread cut it when you first put them in. Not ideal but it’s what I had. M2.5 sized plastic screws with a coarser thread would be better but either way it held fine. This case also leaves the USB accessible.

Anyway, back to the point we now have some nice neat hardware so I tweaked the code to run on this module (different CAN pins to the normal Adafruit CAN shields) and flashed it. After plugging it into the car…nothing happened. Once I’d reflashed the Leonardo with CLK_OUT enabled as per the instructions following a conversation with Hobbytronics who were very helpful (in their defence it says to do it right on the product page but I’d not read that bit!) I loaded it again and when hooked up to the car what I got was the basic warning lights went off, but the immobiliser and power steering that I’d hoped to resolve were still there. Time to delve a bit deeper!

So looking at Dave’s code here’s the bit to resolve the immobiliser:

 if(CAN_MSGAVAIL == CAN0.checkReceive()) { 
  // Check to see whether data is read
 }
    CAN0.readMsgBufID(&ID, &len, buf);    // Read data

        
    //Keyless Control Module and Immobiliser want to have a chat with the PCM, this deals with the conversation
    
    if(ID == 0x47) { //71 Dec is 47 Hex - Keyless Chat
      
      //***** Fixed Coding for Dave Blackhurst's Car *******
      if(buf[1] == 127 && buf[2] == 2) {      
        // Look for 0x 06 7F 02 00 00 00 00 00
      }
        CAN0.sendMsgBuf(0x041, 0, 8, send41a);// 0x041 = 65
        // send41a = 0x 07 0C 30 F2 17 00 00 00
      }
      if(buf[1] == 92 && buf[2] == 244) {     
        // Look for 0x 08 5C F4 65 22 01 00 00
      }
        CAN0.sendMsgBuf(0x041, 0, 8, send41b);
        // send41b = 0x 81 7F 00 00 00 00 00 00
      }

I’ve added in the codes being looked for or sent in each case which Dave identified from scanning the bus on his RX8 just to make it easier to see what’s going on. Breaking this down ID 0x47 is the immobiliser module sending data out which generally seems to just keep repeating 0x06 01 FF 00 00 00 00 00 when in normal use with the car running as factory I have that from my previous logs. So this first code starting 0x 06 7F 02 is something from the immobiliser which triggers the exchange. The code basically just reads any incoming data then checks the ID is 0x47 (i.e. it’s coming from the immobiliser) and that two bytes match the what he knows the CAN data should be (simpler than checking the whole code) , specifically byte 1 being 127 (7F) and byte 2 being 2. He then sends the recorded response to this (send41a – 0x 07 0C 30…) back to the immobiliser which would normally be done by the PCM (ECU) in the car when present. Then we look for the response from the immobiliser matches what we expect (0x 08 5C F4….) and sends a second reply to the immobiliser (send41b – 0x 81 7F 00….). I started thinking the module wasn’t talking to the CANbus right but after some fault finding and adding a diagnostic LED blink at critical points I found it was on the bus but just wasn’t seeing the right data coming from the immobiliser to respond to. Now I knew this exchange worked on Dave’s car but not on mine so clearly the codes we have aren’t universal in some way but I needed to work out what was going on but at least I knew what to look for.

Back when I was trying to find the code to disable the power steering light from Labview I bought a device called the USBtin which is a neat little PCB which is basically just a USB to CAN adapter but it has a built in protocol to control it so you can read the data via software like Putty or relative easily develop custom applications to connect to it. Now facing this problem I decided to give it a go and see if it was actually fast enough to catch this exchange in the first few fractions of a second of the ignition being on. I blew the dust of the original ECU for the car and hooked it back up to the bus (there’s no engine but I hoped that wouldn’t matter for this bit) loaded the basic USBtinViewer onto a tabled and hooked it up.

Ok it’s a photo of a tablet screen but anyway, the point is the USBtin is clearly fast enough to catch all the data because the monitor mode shows it’s caught the exchange because it’s logged packets to ID 0x41 and 0x47 and the last message to 0x41 matches the last one from Dave’s car (send41b – 0x 81 7F…). So it’s got the data, unfortunately to see what was sent both ways I had to trawl through the trace mode which just lists every CAN packet on the bus but after a bit of searching I found this:

So going through it first and ignoring all the extra data (there will be more to follow on this) there’s the default message from the immobiliser sending 06 01 FF… highlighted in yellow, then shortly afterward we see what looks very similar to Dave’s first message of the exchange but where his was 0x 06 7F 02, mine critically is 0x 06 7F 01. Looking back to Dave’s code for this we find that he was specifically looking for byte 2 = 2 and mine is 1, which is probably why it never triggered on my car. Now because that first packet we need to match starts 0x 06 7F … on both cars I can just change the check to look for that combination instead but at this point I also realised the outgoing data from the ECU (0x 07…) and return from the immobiliser (0x 08…) are totally different for my car so rather than mess about I just swapped out both to match what I’d logged for my car (assuming the codes may be car specific to stop PCM’s (ECU’s) being swapped between vehicles they’re not coded to or something) and tried it again, but this time…

Yes this time it cleared the security light! Definitely progress!

But for me making it work isn’t really enough and I like to understand why something works and hopefully make it better!

First off I tried again but this time with the matching done using the updated positions for the consistent bits of the code common to both cars. Specifically getting rid of the check for the byte 2 being any value because this appeared to change from car to car. What we can reasonably assume is fixed from this data is byte 0 because they always seem to indicate the step in the exchange with the exception of the initialisation state and first request state which both start “06” however byte 1 gives us if the immobiliser is still starting (0x 06 01…) and making a request to the PCM (0x 06 7F) and these match on both cars. We then send back one of the first response packets (0x 07….) and wait for the next request which byte comparing the data both cars start with byte 0 = 08 and based on the rest it’s reasonable to assume again this is the sequence step and so universal. Then Dave looks for a value of byte 2 which differs between our cars, however I have noticed that byte 5 for both cars is always 01 so this would work for both. So we end up with this :

      
      byte send41a[8] = {7,120,192,226,94,0,0,0};                      
      // Reply to 47 first  : 0x 07 78 C0 E2 5E 00 00 00 
      // Bytes 0 is the same, bytes 3 & 4 dont seem to matter, 
      // 5,6,7 are zero
      
      byte send41b[8] = {129,127,0,0,0,0,0,0};                         
      // Reply to 47 second : 0x 81 7F
      
      //***** Fixed Coding for Jon's Car *******
      // Some experimentation showed that on the initial request
      // for my car byte 2 was a 01 not a 02
      // however all codes so far begin 06 7F 
      // for either car so this was used.
      // Similarly in the second message from the 
      // immobiliser bytes 1-4 change but byte 5 
      // is always 01 on either vehicle

      if(buf[0] == 0x6 && buf[1] == 0x7F ) {                      
        // 0x 06 7F 01 00 00 00 00 32
        
        // printhex(buf,8);                                        
        // Transmit out received request on debug serial port 
        // - breaks timings on vehicle.
        
        CAN0.sendMsgBuf(0x041, 0, 8, send41a);                    
        // 0x 07 78 C0 E2 5E 00 00 00 
      }
      if(buf[0] == 0x8 && buf[5] == 0x1 ) {                        
        // 0x 08 94 29 BC 91 01 00 32
        
        CAN0.sendMsgBuf(0x041, 0, 8, send41b);                     
        // 0x 81 7F 00 00 00 00 00 00  
      }

I’ve included the notes I made at the time – the printhex is a function I wrote to dump these arrays out to the serial port easily as two digit hex pairs for monitoring what’s going on at different times. As noted here it breaks the timings of the exchange between the ECU and immobiliser but if we want to check something we just add it in and at least we can see what the data was. I’ll do a separate post for that as it might be useful to others. Not unexpectedly matching in this way worked fine but more interestingly I tried my car with Dave’s codes matching in this new way and interestingly it actually worked with no security light…

Well that raises even more questions because in theory I’d just swapped my ECU for his (in terms of the code exchange at least) and it authenticated!

So I went back to my car, reconnected the original ECU, powered it up with the USB logger again and noticed that each time I turned my ignition on the code exchange was different so clearly the idea of the code being fixed for a pair of ECU and immobiliser was wrong. After a number of goes and recording all the results a few things started to become apparent.

Firstly the initial request from the immobiliser had some variations on bytes 7 and 8 which always matched the byte 7 and 8 in the second request but the bytes we look for (byte 0 and 1 shown in green) are always 06 7F in every try.

Second, the first response given by the ECU indeed always starts 07 (light blue), but the next 4 bytes change each time the ignition is turned on (bright blue).

Third, bytes 0 and 5 in the second request are always 08 and 01 respectively (orange) however the 4 bytes between change each time the ignition is turned on (yellow).

Fourth, the second response is always the same (pink).

So what I think is going on here is actually something slightly different. If we assume for a moment the ECU knows the code or processing going on in the immobiliser we get a proper challenge/response interaction. I think the first message sent by the immobiliser is basically a “ready” message telling the ECU to send a block of data. The ECU then responds with a 4 byte block of data which is randomised each start. The immobiliser then performs some function we don’t know and sends the result back to the ECU where it checks the result against what it should be and gives a pass or fail back to the immobiliser so it updates the dash light. The last packet is always the same because we’re using everything from one car so its a pass so we don’t know what a mismatch fail looks like yet but I’m going to look into this at some point.

Now the interesting result of this outcome is with our Arduino we’re not checking if the code response actually matches and if my theory is right the outbound 4 bytes can be absolutely anything as it’s basically just a seed value, then the immobiliser will will reply with a coded version which we just ignore and so long as we reply with a pass message at that point (0x 81 7F 00 00 00 00 00 00)the immobiliser turns the dash light off.

To prove this out I set up the Arduino to send different random numbers in each of bytes 1-4 to the immobiliser in the initial response and indeed while the response from the immobiliser bytes 1-4 change as in response the immobiliser light went out on the dash every time.

My final theory is that the immobiliser module is reading the data from the chip in the key, and using that to transform the initial data from the ECU to create the response and since the ECU knows the key code and whatever this transformation is it knows if it’s the right key or not.

Now hopefully that problems solved for all RX8’s, I’m aware I haven’t posted a full, complete code like I have done previously but that’s because it has all sorts of other features going in this currently and I’ve not finished and tidied the rest of it yet. I’ve also considered the situation where there might be an RX8 out there that doesn’t match the code pattern found in my current sample of two vehicles so I’ve actually added a feature where if you jumper a wire onto a digital input and connect the Arduino to a car with the original ECU in place it will read out the entire code exchange and store all the codes for that car in EEPROM on the Arduino. If you then take the jumper off and pull out the ECU, when you turn the ignition on again the Arduino will use the codes it just stored instead of the defaults. Again I’ll write this up properly when it’s all finished.

Finally thanks to Dave Blackhurst for your work on this. While your solution didn’t work for my immobiliser it gave me the drive to have another go and enough information to go in the right direction and hopefully we’re a step closer to a universal engine/motor swap solution for everyone.

More to follow!

RX8 Engine Swap Project Intro

So the RX8 project involves making what is effectively a worthless vehicle useful again. For anyone not familiar with the Mazda RX8 they are a fairly high spec 4 seater car which is most widely known because it uses a Wankle rotary engine. This type of engine does not use pistons and so is incredibly smooth in operation and in the higher power (231) version of the car revs to 10,000 RPM as standard.

Sadly for all its good points the engine has a number of down sides. In terms of behavior the engine shares a number of similarities to a two stroke piston engine, one aspect is that it is designed to burn oil in normal operation to such an extent it actually has mechanical components to inject oil into the combustion chamber. This means the oil needs to be topped up frequently and it is recommended to check it every time the fuel is filled, though this isn’t as easy it probably should be and very few people do so. As a result many engines fail rapidly due to lack of lubrication once the oil gets low.

The other common failure is with the o-rings which seal the sections of the engine to each other if these fail water gets into the combustion chamber when the cooling system is under pressure (i.e. once the engine is hot). This is one common cause of the warm start/idle problems and where water gets into the oil you get lack of lubrication failure eventually as well.

The engines are expensive to get repaired assuming the fault is detected early enough and no major damage has occurred. If major damage has occurred then sections or even the whole engine may need replacement. Either way the repair is likely to cost more than the car is actually worth and this seems to happen at something around 60-80,000 miles. The combination of all of this is that these cars are abundantly available for very little money with engines in  varying degrees of failure but with relatively few miles on the clock. This leads us nicely to exhibit A:

Cheap RX8
Cheap RX8

This is a 55 plate RX8 I bought from ebay for grand total of £300 taken on the day I bought it in July 2015. While technically still road legal at this stage the car wouldn’t idle when warm so was not drive-able for any real distance without serious difficulty. In order to collect it I had to impose on a friend who has a van and car trailer for moving his racing car.

My plan for the car was to remove the engine and dismantle it to see how far gone the internals were and if possible repair the engine and reinstall it. Failing that the backup plan was to try to swap in an engine from something else simply because buying a working replacement rotary engine would cost approximately £3500!

So having got the car home the next day we started taking things out:

This may look a little unconventional but in the UK the RX8 was Thatcham security rated. Part of this involved preventing the ECU from being removed because otherwise any wannabe car thief could just swap the ECU for one from a scrap yard for which they have the matching immobiliser chip, then either hotwire it or force the ignition lock like older pre-immobiliser cars. RX8’s from other countries do not have the steel retaining plates as they do not have this rating. Since the retaining bars (gold in the picture) were several mm thick and held in place with any number of rivets the only option (well the only one we could come up with at short notice) was to drill the rivets outs. I recommend centre punching (creating a divot in the centre) the rivets before drilling because they are domed and the drill will skid off. Now technically you could probably remove all the plugs on the engine and leave the ECU in place but we wanted to allow as much room as possible to take the engine out.

Unfortunately in the RX8 the engine is mounted very low and well back with a lot of ancillaries on top of it making removal a little more time consuming:

RX8 Engine Bay
There’s an engine in there somewhere!

Incredibly the back end of the engine is nearly level with the visible firewall and the front is indicated by the alternator! Yes is really is a very small engine and this particular one is the lower power RX8 – so the output of this engine is *only* 192 bhp!

RX8 Engine bay end of day 1

And this was basically where we got to by the end of our first day removing parts. In truth this is only about three hours in as we’d had something of a heavy night and bright sunlight wasn’t helping the situation!

More to follow shortly…