Reverse-Engineering a Cheap DMR Handheld

2026-10-07 by N8NAT builds

Programming a Cotre CO06D with no real software for it meant talking straight to the radio's debug port and mapping its memory by hand. The best bug turned out to be a reset default hiding as a hardware fault.

Overview

The Cotre CO06D is an inexpensive DMR handheld built on the Auctus A6 chipset. There is no proper programming software for it in this setup, so programming it meant talking directly to the radio’s debug serial port and working out where it keeps its channels, contacts, and settings. This is what that took.

Background

The radio exposes a debug UART that answers a set of AT-style commands. The first lesson was mundane and cost time anyway: the cable matters. Common PL2303 cables failed outright. A CH340 or FTDI cable worked. With a working cable, the radio would talk.

Build / Process

The codeplug lives in RAM, then gets committed. Channels and contacts sit in tables in the radio’s RAM. Edits there are not permanent until they are committed to non-volatile memory, and a write that is not committed is simply lost on the next power cycle. So every change is write-then-commit.

Writes are whole-word or they corrupt. The memory interface writes a full word at a time. A partial write clobbers the rest of the word, which quietly corrupts the neighboring data. Respecting the word boundary was the difference between a clean edit and a scrambled table.

The best bug was a reset default. The radio would not come up correctly on the hotspot, and it looked like a frequency or hardware problem. It was not. A factory reset wipes the radio’s DMR ID to 201, and a hotspot rejects a radio identifying as 201. The wake-up handshake just fails. The radio was fine. Its identity had been erased. The fix was to have the programming preset set the DMR ID explicitly, so a reset can never leave it as 201.

A reboot on received calls. When a call arrived from a sender that matched a contact already written to the radio, the radio rebooted. The cause was in the contact records: each needs a unique key in RAM, and those keys have to stay within the contact count. Giving every contact a proper unique key stopped the reboots.

Dumping the flash. Reading the whole flash out at once stalled, so it came out in small chunks instead, which read cleanly. That dump contains sensitive key material, so it stays contained and off the air and off the internet. The point of the dump was to map the layout, not to publish it.

Alongside the radio work, the hotspot itself needed a small patch to answer the particular DMR wake-up the Cotre sends, which is what let it register at all.

Results

The radio now programs from the Pi, holds its configuration across power cycles, decodes on the hotspot, works on BrandMeister through it, and passes the parrot test. A radio that shipped with no usable programming path is a usable DMR handheld.

Lessons

  • Cheap radios hide real complexity. The “software” is often a thin shell over a debug protocol. Once you talk to the port directly, you own the whole memory map, and all of its sharp edges.
  • Respect the memory model. Whole-word writes, commit after every change. Skip either and you corrupt the codeplug.
  • Check the boring thing first. The worst-looking bug was a reset default setting the ID to 201. It presented as hardware. It was a number.