I’m now confident with the tools I have to further sniff and try to reproduce the MEMS 2J protocol so let’s try and get more data by seeing what the responses of the ECU are. For this test I am simply initiating communication on the ACR4 but not performing any further action.
Looks like we have lots of data going back and forth!!!
I’ve done three separate runs of the same test (to see if the commands/responses are ever different) and these are the results:
Run 1
TX: 81 13 F7 81 0C
RX: 03 C1 D5 8F 28
TX: 02 10 A0 B2
RX: 01 50 51
TX: 02 27 01 2A
RX: 04 67 01 96 A4 A6
TX: 04 27 02 D9 34 3A
RX: 02 67 02 6B
TX: 02 3E 01 41
RX: 01 7E 7F
Command above repeats...
Run 2
TX: 81 13 F7 81 0C
RX: 03 7F 81 10 13
TX: 02 10 A0 B2
RX: 01 50 51
TX: 02 27 01 2A
RX: 04 67 01 00 00 6C
TX: 04 27 02 00 01 2E
RX: 04 67 01 00 00 6C
TX: 02 3E 01 41
RX: 01 7E 7F
Command above repeats...
Run 3
TX: 81 13 F7 81 0C
RX: 03 7F 81 10 13
TX: 02 10 A0 B2
RX: 01 50 51
TX: 02 27 01 2A
RX: 04 67 01 00 00 6C
TX: 04 27 02 00 01 2E
RX: 04 67 01 00 00 6C
TX: 02 3E 01 41
RX: 01 7E 7F
Command above repeats...
As we can see from the three runs, there is a certain degree of variability in the commands and responses - run 2 and 3 happen to match but run 1 is different.
There is a distinct pattern in the commands and responses though which will help us understand what’s being sent and responded to. For both the command and response case, the first byte always appears to be the length without the checksum byte. For the response, the second byte always appears to be the second byte of the command + 0x40! This does not ring true for the first command (apart from the length byte) which I imagine is a special initialisation command/response.
As the ACR4 continually repeats the final command shown (02 3E 01 41), I believe this to be a heartbeat command or ping to keep the communications open. My plan is to initially establish comms using librosco and maintain this using the same heartbeat command. As there appears to be no difference in the initial command sent then I will simply use this and ignore the following 3 commands prior to sending the heartbeat. Let’s make some changes to librosco and see if we can communicate with the ECU:
Using MEMS 2J
Running command: heartbeat
mems_read_serial(): read 1 bytes, expected 1: 00
mems_send_command_with_checksum(): sending command...
mems_write_serial(): writing 1 bytes: 81
mems_write_serial(): writing 1 bytes: 13
mems_write_serial(): writing 1 bytes: F7
mems_write_serial(): writing 1 bytes: 81
mems_send_command_with_checksum(): sending checksum...
mems_write_serial(): writing 1 bytes: 0C
mems_send_command_with_checksum(): reading back echoed bytes...
mems_read_serial(): read 1 bytes, expected 1: 81
mems_read_serial(): read 1 bytes, expected 1: 13
mems_read_serial(): read 1 bytes, expected 1: F7
mems_read_serial(): read 1 bytes, expected 1: 81
mems_send_command_with_checksum(): reading back echoed checksum...
mems_read_serial(): read 1 bytes, expected 1: 0C
mems_read_response_with_checksum(): reading length byte...
mems_read_serial(): read 1 bytes, expected 1: 03
mems_read_response_with_checksum(): reading response bytes...
mems_read_serial(): read 3 bytes, expected 3: C1 D5 8F
mems_read_response_with_checksum(): reading checksum byte...
mems_read_serial(): read 1 bytes, expected 1: 28
ECU responded to initialization with: 00 00 00 00
mems_send_command_with_checksum(): sending command...
mems_write_serial(): writing 1 bytes: 02
mems_write_serial(): writing 1 bytes: 3E
mems_write_serial(): writing 1 bytes: 01
mems_send_command_with_checksum(): sending checksum...
mems_write_serial(): writing 1 bytes: 41
mems_send_command_with_checksum(): reading back echoed bytes...
mems_read_serial(): read 1 bytes, expected 1: 02
mems_read_serial(): read 1 bytes, expected 1: 3E
mems_read_serial(): read 1 bytes, expected 1: 01
mems_send_command_with_checksum(): reading back echoed checksum...
mems_read_serial(): read 1 bytes, expected 1: 41
mems_read_response_with_checksum(): reading length byte...
mems_read_serial(): expected 1, got -1
mems_read_response_with_checksum(): failed to read response length byte
It looks like it is working to some extent, at least we’re getting bytes back from the ECU with valid checksums so the communication method appears to be working. Occasionally, we do not read a response though - perhaps something in the timing:


The logic analyser shows that following the last received byte of the initialisation command there is a 100ms pause before the next command and all commands after this there is a 50ms pause between commands. Adding this in to librosco gives reliable comms over 3 separate runs, at least for the heartbeat command!
Using MEMS 2J
Running command: heartbeat
mems_read_serial(): read 1 bytes, expected 1: 00
mems_send_command_with_checksum(): sending command...
mems_write_serial(): writing 1 bytes: 81
mems_write_serial(): writing 1 bytes: 13
mems_write_serial(): writing 1 bytes: F7
mems_write_serial(): writing 1 bytes: 81
mems_send_command_with_checksum(): sending checksum...
mems_write_serial(): writing 1 bytes: 0C
mems_send_command_with_checksum(): reading back echoed bytes...
mems_read_serial(): read 1 bytes, expected 1: 81
mems_read_serial(): read 1 bytes, expected 1: 13
mems_read_serial(): read 1 bytes, expected 1: F7
mems_read_serial(): read 1 bytes, expected 1: 81
mems_send_command_with_checksum(): reading back echoed checksum...
mems_read_serial(): read 1 bytes, expected 1: 0C
mems_read_response_with_checksum(): reading length byte...
mems_read_serial(): read 1 bytes, expected 1: 03
mems_read_response_with_checksum(): reading response bytes...
mems_read_serial(): read 3 bytes, expected 3: C1 D5 8F
mems_read_response_with_checksum(): reading checksum byte...
mems_read_serial(): read 1 bytes, expected 1: 28
ECU responded to initialization with: 00 00 00 00
mems_send_command_with_checksum(): sending command...
mems_write_serial(): writing 1 bytes: 02
mems_write_serial(): writing 1 bytes: 3E
mems_write_serial(): writing 1 bytes: 01
mems_send_command_with_checksum(): sending checksum...
mems_write_serial(): writing 1 bytes: 41
mems_send_command_with_checksum(): reading back echoed bytes...
mems_read_serial(): read 1 bytes, expected 1: 02
mems_read_serial(): read 1 bytes, expected 1: 3E
mems_read_serial(): read 1 bytes, expected 1: 01
mems_send_command_with_checksum(): reading back echoed checksum...
mems_read_serial(): read 1 bytes, expected 1: 41
mems_read_response_with_checksum(): reading length byte...
mems_read_serial(): read 1 bytes, expected 1: 01
mems_read_response_with_checksum(): reading response bytes...
mems_read_serial(): read 1 bytes, expected 1: 7E
mems_read_response_with_checksum(): reading checksum byte...
mems_read_serial(): read 1 bytes, expected 1: 7F
mems_send_command_with_checksum(): sending command...
mems_write_serial(): writing 1 bytes: 02
mems_write_serial(): writing 1 bytes: 3E
mems_write_serial(): writing 1 bytes: 01
mems_send_command_with_checksum(): sending checksum...
mems_write_serial(): writing 1 bytes: 41
mems_send_command_with_checksum(): reading back echoed bytes...
mems_read_serial(): read 1 bytes, expected 1: 02
mems_read_serial(): read 1 bytes, expected 1: 3E
mems_read_serial(): read 1 bytes, expected 1: 01
mems_send_command_with_checksum(): reading back echoed checksum...
mems_read_serial(): read 1 bytes, expected 1: 41
mems_read_response_with_checksum(): reading length byte...
mems_read_serial(): read 1 bytes, expected 1: 01
mems_read_response_with_checksum(): reading response bytes...
mems_read_serial(): read 1 bytes, expected 1: 7E
mems_read_response_with_checksum(): reading checksum byte...
mems_read_serial(): read 1 bytes, expected 1: 7F
Looks like we’re getting somewhere! Next step is to actually get some data...