Reverse Engineering the Baofeng dm1702 codeplug M0YNG.uk

Created 2020-06-17

Modified 2020-08-03

Tagged

A note from the future that goes at the start

I started working on this nearly two month ago, and I've not had time to get any further with it. So I'm going to post this now, incomplete as it is, in the hopes it might be useful to someone else, or my future self if I get back to it at some point.

Some background

Recently I was too tempted by the seemingly very good price of the Baofeng dm1702 DMR radio.

I paid £65 for the radio, which included delivery, which seemed reasonable considering the features

I didn't do enough research though, I just assumed that there would be tools available to help me code it up in Linux, as there are for so many DMR radios, but sadly all I can find right now is some stuff to write data to and from the radio, which works, but doesn't help me change any settings like dmrconfig does for my Anytone.

So I resorted to the official software, which only works in windows, which means I had to kick my offline VM into gear. But oh my, is that software bad, like, really, really bad.

When editing a table of channels, you can't tab between them, it sorts by name so adding a new row goes wherever the default text fits in the sorting order, etc. etc. etc.

It is so bad I decided to break out a hex editor and try to work out what is going on in the codeplug itself.

An initial look

Now, I'm not an expert at reverse engineering anything, so I don't expect to be able to actually do this task…

A first look wasn't promising, there is lots of empty space, lots of FFFF, lots of repeating data that doesn't appear to store anything meaningful.

Next I made one small change to the codeplug, and tried to diff it, here I have changed my hotspot frequency from 438.8MHz to 136.12345MHz on RX and 444.67899 on TX:

$ diff  <(xxd codeplug-justfreq.data) <(xxd codeplug.data)
833c833
< 00003400: 4523 6113 9978 4644 4000 0000 0000 1100  E#a..xFD@.......
> 00003400: 4523 6113 9978 4644 4200 0000 0000 1100  E#a..xFDB.......

Thanks to a great tip from SP6MR who identified the values as being stored as unsigned 32bit I started to get somewhere. Maybe.

A change of tense

You might notice a tense change now, as I'm writing this post as I work, mostly to keep notes for myself!

We can also see that changing the TX power level from low to high changes the value after the frequency from 40 to 42

< 00003400: 4523 6113 9978 4644 4000 0000 0000 1100  E#a..xFD@.......
> 00003400: 4523 6113 9978 4644 4200 0000 0000 1100  E#a..xFDB.......

Changing the timeslot from 2 to 1 and the last chunk changes from 11 to 10

< 00003400: 4523 6113 9978 4644 4000 0000 0000 1100  E#a..xFD@.......
> 00003400: 4523 6113 9978 4644 4200 0000 0000 0100  E#a..xFDB.......

But wait! changing the colour code from 1 to 2 makes that 11 or 10 into 12 or 02, so we must be storing the timeslot in one bit, counting from zero

< 00003400: 4523 6113 9978 4644 4000 0000 0000 1100  E#a..xFD@.......
> 00003400: 4523 6113 9978 4644 4200 0000 0000 1200  E#a..xFDB.......

Which makes me wonder about our conclusion for the TX power…

< 00003400: 4523 6113 9978 4644 4000 0000 0000 1100  E#a..xFD@.......
> 00003400: 4523 6113 9978 4644 0000 0000 0000 1200  E#a..xFD........

Based on that, the 40 is actually 4 for DMR/Digital and 0 for analogue, with the other bit storing the TX power level as 0 or 2.

We also see another line change much further through the file:

< 0001e020: 000e 0009 000b 0100 000d 0100 0000 ffff  ................
> 0001e020: 000e 0009 000b 0100 000d 0000 0000 ffff  ................

Only one bit seems to change though, so I don't know what it's for (yet?)

Next I changed it back to a digital channel, and set the "TX Contact Name"

< 0001e020: 000e 0009 000b 0100 000d 0100 0000 ffff  ................
> 0001e020: 000e 0009 000b 0100 000d 0005 0000 ffff  ................

It seems that the 6th chunk has some bits that changes to a number referring to the contact (somehow).

Around 0001F000 we see what looks like the name of contacts

0001f000: ffff 5357 204f 6869 6f20 4b34 5553 4400  ..SW Ohio K4USD.
0001f010: 0000 ffa2 7a00 04ff ffff 3331 3035 3537  ....z.....310557
0001f020: 204d 6169 6e00 0000 0000 ff1d bd04 04ff   Main...........
0001f030: ffff 3331 3639 204d 6964 5765 7374 0000  ..3169 MidWest..
0001f040: 0000 ff61 0c00 04ff ffff 4172 6561 2038  ...a......Area 8
0001f050: 2033 3130 3938 0000 0000 ff7a 7900 04ff   31098.....zy...
0001f060: ffff 3331 3020 5441 4300 0000 0000 0000  ..310 TAC.......
0001f070: 0000 ff36 0100 04ff ffff 3331 3120 5441  ...6......311 TA
0001f080: 4300 0000 0000 0000 0000 ff37 0100 04ff  C..........7....
0001f090: ffff 3331 3220 5441 4300 0000 0000 0000  ..312 TAC.......
0001f0a0: 0000 ff38 0100 04ff ffff 3331 3030 2055  ...8......3100 U
0001f0b0: 5341 0000 0000 0000 0000 ff1c 0c00 04ff  SA..............
0001f0c0: ffff 3933 204e 2041 6d65 7269 6361 0000  ..93 N America..
0001f0d0: 0000 ff5d 0000 04ff ffff 3331 3339 204f  ...]......3139 O
0001f0e0: 6869 6f20 5769 6465 0000 ff43 0c00 04ff  hio Wide...C....
0001f0f0: ffff 576f 726c 6445 6e67 6c69 7368 2039  ..WorldEnglish 9

Each Name seems to be 16 characters long, and have something after the text. This repeats for 800 calls, ending at 00023B40, where we have FF until 00024000 where we get 00 until 00025020.

Changing the call ID causes a change, but it's not clear how the data is stored, it doesn't appear to be unsigned 32bit. Here I've changed the ID from 310 to 111

< 0001f070: 0000 ff36 0100 04ff ffff 3331 3120 5441  ...6......311 TA
> 0001f070: 0000 ff6f 0000 04ff ffff 3331 3120 5441  ...o......311 TA

Based on Andy Valencia's keen eyes the ID is being stored in "endian shuffled order", as can be seen here with the ID 11111111 as c7, then 8a, and a9, read each two together, but backwards and we get 0xa98ac7

0001f070: 5354 ffc7 8aa9 04ff ffff 3331 3120 5441  ST........311 TA

If we change the ID to 11111113 we have even more confidence we're doing it right

0001f070: 5354 ffc9 8aa9 04ff ffff 3331 3120 5441  ST........311 TA

Structure of a contact

At this point, I think the structure of a contact is:

Making 24 bytes in total per contact.

Structure of a memory

3410 offset

0001e020 offset

Make a memory by hand

In theory we know enough to try making a memory by hand now, I'm going to try GB3CG, a local analogue repeater on 2m.

I think it will look like this:

0025 5714 0025 5114 0200 0000 0000 0000
0000 1881 1188 1000 0000 0000 0000 0000

I manually edited the codeplug in Okteta and wrote it to the radio, and it half worked!

CTCSS was wrong, it was enabled but had the wrong value, so I changed it on the radio and read back the changes

< 00003410: 0000 1881 1188 1000 0000 4000 0000 0000  ..........@.....
> 00003410: 0000 1888 1188 1100 0000 4000 0000 0000  ..........@.....

When I remove just the RX CTCSS we get

< 00003410: 0000 1881 1188 1000 0000 4000 0000 0000  ..........@.....
> 00003410: 0000 18ff ff88 1100 0000 4000 0000 0000  ..........@.....

When I remove just the TX CTCSS we get

> 00003410: 0000 18ff ffff ff00 0000 4000 0000 0000  ..........@.....

This suggests that I've not got the CTCSS structure quite right, but what's really happened is I've messed up understanding the structure. The one above is actually the revised version, not what I originally had. Byte 3 on this line needs to be something else, and I'd missed it completely so everything was offset.

Share this post on Mastodon