0

I am reverse engineering the communication protocol used by Makita XGT (40V) batteries. I have successfully captured a number of messages and have some hints at their basic structure, but they appear to have a checksum of some description at the end of each message, and I'm not really sure how to go about figuring out the algorithm.

The code that calculates them only exists on microcontroller ICs and at this point I do not think the firmware can be dumped, however the algorithm seems like it might be simple (because adding 1 to one of the bytes also adds 1 to the checksum) so I'm hoping someone might be able to spot a pattern and shed some light on how they are calculated.

Here are some sample messages. They appear to be 16-bit big endian words, however they are sent as 8-bit bytes so it is possible the checksum works at the 8-bit level, however everything else seems to be 16-bit so I'd probably start there. (The bytes come in over the wire as A5 A5 00 18 which I have written below as A5A5 0018.)

Every message starts with A5A5 so I am not sure whether this is part of the checksum or not - it may be excluded. Messages are padded to the nearest 16-byte (8-word) boundary with FFFF words, and as these come after the checksum word, I presume they are not included in the checksum calculation.

Here is the basic structure of the messages, with apologies for my ASCII art:

|||| Message header/signature/sync (always A5A5)
||||
||||   | Message length (bit flags)
||||   |
||||   |   ||| Message ID (010)
||||   |   |||                          |||| Requesting two parameters (1201 and 120D)
||||   |   |||                          ||||
||||   |   |||                          ||||           |||| Checksum to be examined
||||   |   |||                          ||||           ||||    (ignore FFFF padding)
A5A5 0018 5010 4D4C 00CC 120D 0008 0003 0002 1201 120D 023B FFFF FFFF FFFF FFFF
        | |
        | | 5 = message from charger to battery
        | | 9 = reply from battery to charger
        |
        | Number of padding bytes (8 bytes = 4 FFFF words)

Here is some sample data, one message per line:

// Message IDs starting at 01A
A5A5 0018 501A 4D4C 00CC 120D 0008 0003 0002 1201 120D 0245 FFFF FFFF FFFF FFFF
A5A5 0018 501B 4D4C 00CC 120D 0008 0003 0002 1201 120D 0246 FFFF FFFF FFFF FFFF
A5A5 0018 501C 4D4C 00CC 120D 0008 0003 0002 1201 120D 0247 FFFF FFFF FFFF FFFF
A5A5 0018 501D 4D4C 00CC 120D 0008 0003 0002 1201 120D 0248 FFFF FFFF FFFF FFFF
A5A5 0018 501E 4D4C 00CC 120D 0008 0003 0002 1201 120D 0249 FFFF FFFF FFFF FFFF
A5A5 0018 501F 4D4C 00CC 120D 0008 0003 0002 1201 120D 024A FFFF FFFF FFFF FFFF
A5A5 0018 5020 4D4C 00CC 120D 0008 0003 0002 1201 120D 024B FFFF FFFF FFFF FFFF
A5A5 0018 5021 4D4C 00CC 120D 0008 0003 0002 1201 120D 024C FFFF FFFF FFFF FFFF
A5A5 0018 5022 4D4C 00CC 120D 0008 0003 0002 1201 120D 024D FFFF FFFF FFFF FFFF
A5A5 0018 5023 4D4C 00CC 120D 0008 0003 0002 1201 120D 024E FFFF FFFF FFFF FFFF
A5A5 0018 5024 4D4C 00CC 120D 0008 0003 0002 1201 120D 024F FFFF FFFF FFFF FFFF
A5A5 0018 5025 4D4C 00CC 120D 0008 0003 0002 1201 120D 0250 FFFF FFFF FFFF FFFF
A5A5 0018 5026 4D4C 00CC 120D 0008 0003 0002 1201 120D 0251 FFFF FFFF FFFF FFFF
A5A5 0018 5027 4D4C 00CC 120D 0008 0003 0002 1201 120D 0252 FFFF FFFF FFFF FFFF
A5A5 0018 5028 4D4C 00CC 120D 0008 0003 0002 1201 120D 0253 FFFF FFFF FFFF FFFF
A5A5 0018 5029 4D4C 00CC 120D 0008 0003 0002 1201 120D 0254 FFFF FFFF FFFF FFFF
A5A5 0018 502A 4D4C 00CC 120D 0008 0003 0002 1201 120D 0255 FFFF FFFF FFFF FFFF

// Chunk 2: same message IDs as above, but different message length
A5A5 001C 501A 4D4C 00CC 120C 0004 2101 0100 0230 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 501B 4D4C 00CC 120C 0004 2101 0100 0231 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 501C 4D4C 00CC 120C 0004 2101 0100 0232 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 501D 4D4C 00CC 120C 0004 2101 0100 0233 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 501E 4D4C 00CC 120C 0004 2101 0100 0234 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 501F 4D4C 00CC 120C 0004 2101 0100 0235 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5020 4D4C 00CC 120C 0004 2101 0100 0236 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5021 4D4C 00CC 120C 0004 2101 0100 0237 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5022 4D4C 00CC 120C 0004 2101 0100 0238 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5023 4D4C 00CC 120C 0004 2101 0100 0239 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5024 4D4C 00CC 120C 0004 2101 0100 023A FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5025 4D4C 00CC 120C 0004 2101 0100 023B FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5026 4D4C 00CC 120C 0004 2101 0100 023C FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5027 4D4C 00CC 120C 0004 2101 0100 023D FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5028 4D4C 00CC 120C 0004 2101 0100 023E FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5029 4D4C 00CC 120C 0004 2101 0100 023F FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 502A 4D4C 00CC 120C 0004 2101 0100 0240 FFFF FFFF FFFF FFFF FFFF FFFF

// Checksum carries (2FF -> 300)
A5A5 001C 50E6 4D4C 00CC 120C 0004 2101 0100 02FC FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50E7 4D4C 00CC 120C 0004 2101 0100 02FD FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50E8 4D4C 00CC 120C 0004 2101 0100 02FE FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50E9 4D4C 00CC 120C 0004 2101 0100 02FF FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50EA 4D4C 00CC 120C 0004 2101 0100 0300 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50EB 4D4C 00CC 120C 0004 2101 0100 0301 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50EC 4D4C 00CC 120C 0004 2101 0100 0302 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50ED 4D4C 00CC 120C 0004 2101 0100 0303 FFFF FFFF FFFF FFFF FFFF FFFF

// Checksum jumps when message ID carries (0FF -> 100)
A5A5 001C 50FC 4D4C 00CC 120C 0004 2101 0100 0312 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50FD 4D4C 00CC 120C 0004 2101 0100 0313 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50FE 4D4C 00CC 120C 0004 2101 0100 0314 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 50FF 4D4C 00CC 120C 0004 2101 0100 0315 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5100 4D4C 00CC 120C 0004 2101 0100 0217 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5101 4D4C 00CC 120C 0004 2101 0100 0218 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5102 4D4C 00CC 120C 0004 2101 0100 0219 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5103 4D4C 00CC 120C 0004 2101 0100 021A FFFF FFFF FFFF FFFF FFFF FFFF

// As per Chunk 2 above, but message IDs are now +100, checksums are +1 in comparison
A5A5 001C 511A 4D4C 00CC 120C 0004 2101 0100 0231 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 511B 4D4C 00CC 120C 0004 2101 0100 0232 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 511C 4D4C 00CC 120C 0004 2101 0100 0233 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 511D 4D4C 00CC 120C 0004 2101 0100 0234 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 511E 4D4C 00CC 120C 0004 2101 0100 0235 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 511F 4D4C 00CC 120C 0004 2101 0100 0236 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5120 4D4C 00CC 120C 0004 2101 0100 0237 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5121 4D4C 00CC 120C 0004 2101 0100 0238 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5122 4D4C 00CC 120C 0004 2101 0100 0239 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5123 4D4C 00CC 120C 0004 2101 0100 023A FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5124 4D4C 00CC 120C 0004 2101 0100 023B FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5125 4D4C 00CC 120C 0004 2101 0100 023C FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5126 4D4C 00CC 120C 0004 2101 0100 023D FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5127 4D4C 00CC 120C 0004 2101 0100 023E FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5128 4D4C 00CC 120C 0004 2101 0100 023F FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 5129 4D4C 00CC 120C 0004 2101 0100 0240 FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 001C 512A 4D4C 00CC 120C 0004 2101 0100 0241 FFFF FFFF FFFF FFFF FFFF FFFF

// Random assortment of other messages
A5A5 0018 5007 4D4C 00CC 1204 0008 2101 0008 2109 0000 0246 FFFF FFFF FFFF FFFF
A5A5 0000 9007 4D4C 00CC B204 0000 02B2
A5A5 0016 5008 4D4C 00CC 1205 000A 0003 0003 1201 120D 120F 024D FFFF FFFF FFFF
A5A5 0010 9008 4D4C 00CC 3205 0010 0001 0000 1201 0404 120D 0D84 120F 0000 0341
A5A5 001C 5009 4D4C 00CC 120C 0004 2101 0100 021F FFFF FFFF FFFF FFFF FFFF FFFF
A5A5 0000 9009 4D4C 00CC B20C 0000 02BC
A5A5 0018 500A 4D4C 00CC 120D 0008 0003 0002 1201 120D 0235 FFFF FFFF FFFF FFFF
A5A5 0014 900A 4D4C 00CC 320D 000C 0001 0000 1201 0404 120D 0D84 032A FFFF FFFF

Most of the checksums seem to be in the 0200..0300 range, however really long messages can have larger values, such as these ones at powerup that are in the 0700 range, which suggests to me some kind of sum/addition, given that longer messages have larger checksums:

A5A5 0036 5001 4D4C 00CC 1200 002A 2101 0002 2102 2020 4152 3034 4344 2103 0000 2104 0258 2105 0A21 063C 2107 0521 0814 2109 0000 210C E2D0 07D6 FFFF FFFF FFFF
A5A5 0036 5002 4D4C 00CC 1200 002A 2101 0002 2102 2020 4152 3034 4344 2103 0000 2104 0258 2105 0A21 063C 2107 0521 0814 2109 0000 210C E2D0 07D7 FFFF FFFF FFFF

Any insights to a possible algorithm here would be much appreciated!

1 Answer 1

1

Starting A5A5 and trailing FFFF should be excluded.
The checksum is just a 16-bit sum of 8-bit bytes.

A5A5 0018 501A 4D4C 00CC 120D 0008 0003 0002 1201 120D 0245 FFFF FFFF FFFF FFFF
      ^ ^  ^ ^  ^ ^  ^ ^  ^ ^  ^ ^  ^ ^  ^ ^  ^ ^  ^ ^    ^
      \----------------bytes to sum up---------------/  sum

0x00 + 0x18 + ... + 0x12 + 0x0D = 0x0245
1
  • Wow that's even simpler than I expected! Nice job figuring it out so quickly.
    – Malvineous
    Oct 3, 2023 at 10:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.