Adding a Radio to CHIRP

POSTED: 2026-02-21

CHIRP is the de facto standard for programming amateur and consumer radios from a computer. It's free, open source, and supports over 400 radio models from dozens of manufacturers.

I recently added support for several radios across two different hardware platforms. Here's a quick rundown of what that involves.

Two Platforms, Three Confusing Names

Before anything else, the naming needs untangling, because the manufacturers and importers have done their best to make this confusing.

The Radioddity GM-30 is a GMRS handheld with its own CHIRP driver (radioddity_gm30.py). The Radioddity GM-30 Plus and Radioddity GM-30 Pro are completely different radios on a completely different hardware platform—they're variants of a platform CHIRP collectively refers to as Baofeng UV-17Pro GPS, living in baofeng_uv17Pro.py. A lot of radios currently on the market are variants of this basic platform: the GM-30 Plus and Pro have more in common with a Baofeng UV-5G Mini than they do with the radio whose name they share.

I own radios on both sides of this divide, and my contributions ended up touching both driver files. The work fell into two separate stories that happened to run in parallel.

The GM-30 Side: Clones and Ghosts

The GM-30 already had a working CHIRP driver, written by someone else. I have known for a while that the Baofeng GM-15 Pro is the GM-30 with different trim. That "driver" was four lines of code—a class alias. Same firmware version, different shell, different Amazon listing, different price point.

Then came the Radioddity MU-5, which is the MURS variant of the GM-30. Same hardware again, but the firmware restricts it to five MURS frequencies at 2 watts. The implementation detail that surprised me was how channels 1–20 work.

The MU-5's first 20 channels are fixed to the five MURS frequencies in a repeating pattern. You cannot change them. Not from the front panel, not from the CPS software, not from CHIRP. When you read the EEPROM, the RX and TX frequency fields for those channels contain 0xFFFFFFFF—the same value that means "empty" on every other channel. The firmware doesn't store MURS frequencies in the EEPROM at all. It hardcodes them based on channel number and ignores whatever bytes are sitting in those locations.

This means the CHIRP driver has to do something slightly unusual: for channels 1–20, it returns a frequency that isn't in the EEPROM. It computes the MURS frequency from the channel number, marks the frequency/duplex/offset/power fields as immutable (grayed out in the UI), and writes 0xFFFFFFFF back on save, because that's what the official CPS does. It probably doesn't actually matter what we write back, but this seemed safest.

The UV-17Pro GPS Side: Implied Modes

The GM-30 Plus was the bigger piece of work. CHIRP already had a UV-17Pro GPS driver, and it could talk to the GM-30 Plus without errors, but you could program any frequency, any power level, any mode, and CHIRP would happily write it to the radio. The radio would then refuse to transmit because its firmware knew better.

This is a common failure mode in radio programming software: the tool lets you do something the radio won't. The user sees nothing happen on transmit and assumes their radio is broken.

The FCC restricts the 467 MHz interstitial channels (the ones between the repeater pairs) to low power and narrowband. The GM-30 Plus enforces this in firmware: if the computed TX frequency lands on an interstitial channel, the radio forces low power and NFM regardless of what you've programmed.

CHIRP calls this pattern implied modes—when a radio silently overrides a user-programmed setting based on frequency. The question for the driver is: should it lie to the user (show what's actually in the EEPROM) or tell the truth (show what the radio will actually do)?

The answer, per CHIRP convention, is to tell the truth. When you read a memory from the GM-30 Plus, the driver checks the computed TX frequency. If it's an interstitial channel, the driver returns NFM and low power regardless of what the EEPROM says. When you write a memory that violates these constraints, CHIRP issues a warning—not an error. This distinction matters, because the radio also does something surprising: it allows odd splits and arbitrary frequency assignments from the front panel. It just silently inhibits TX if the result isn't a valid GMRS transmit frequency. The driver mirrors this behavior. It warns you, but it doesn't stop you, because the radio doesn't stop you from programming it that way.

When the Family Grows

Two more UV-17Pro GPS variants showed up in the mail shortly thereafter: the Radioddity GM-30 Pro and the Baofeng GM-21. Both are GMRS radios with the same frequency-based TX restrictions, but the Pro adds Bluetooth and a per-channel scramble setting that the BF-K6 had but no other UV-17Pro variant exposed.

At this point it became clear that I should refactor the stuff I had added for the GM-30 Plus into a more general "UV-17Pro GMRS-locked variant" abstraction. I extracted the GMRS validation logic into an intermediate class (UV17ProGPSGMRS) and refactored scramble from a K6-specific feature to a _has_scramble flag on the base class. The three GMRS variants became three thin subclasses differing only in capability flags—_has_gps, _has_bt, _has_scramble.

Contributing to Boring Software

CHIRP is a good example of what its creator calls "successful boring software." It has been around since 2008. It survived a Python 2 to 3 migration and a complete UI rewrite. It has drivers written by people who submitted one PR and disappeared, for radios that are still in active use but no longer manufactured. Changing anything in that codebase is a minefield of implicit assumptions and untestable hardware interactions.

The thing that makes contributing to CHIRP interesting is modeling the behavior of a physical device whose firmware was written by an engineer in Shenzhen who may not have documented their design decisions, for a regulatory environment they may not fully understand, inside a framework that has to round-trip data through a binary EEPROM format without breaking 400 other radios. Every design choice is a negotiation between what the radio does, what the FCC says it should do, what the user expects, and what CHIRP can reasonably represent.

If your radio isn't in CHIRP and you want to fix that, the developer documentation is a solid starting point. If it's a variant of something that already exists, you might be surprised how little code it takes. And if you're lucky, you'll learn something about your radio that even the manufacturer didn't bother to tell you.