The split-name mod
A channel name gets sixteen characters and one line. That is enough room to be technically correct and still unreadable at arm's length.
I want a name that says both things a newcomer needs: what service this is,
and which channel it is. GMRS 16 REPEATER says it, but by the
time it fits on one line it is small enough that you have to stop and look.
What I actually wanted was two lines, both big.
So the mod is simple to use: put a | in the channel name when
you program the radio.
GMRS|16 RPT → GMRS
16 RPT
What it actually does
Every piece of the channel screen — contact, channel name, TX timer,
zone — is drawn by one function:
uiUtilityDisplayInformation() in
application/source/user_interface/uiUtilities.c. The screen
code in uiChannelMode.c doesn't draw anything itself; it calls
that function with a tag saying what kind of line this is:
uiUtilityDisplayInformation(nameBuf, DISPLAY_INFO_CHANNEL, yOverride);
Inside, a switch on that tag picks the rendering rules, so the
whole mod lives under one case label:
case DISPLAY_INFO_CHANNEL:. That's the thing that made this
patch pleasant to write — one function, one case, no hunting across
files.
Before anything is rendered, it looks for a pipe:
const char *pipe = (str != NULL) ? strchr(str, '|') : NULL;
If there's one, the name is cut in two at that point and copied into a pair of sixteen-character buffers. If not, the name is used as-is — the stock path, untouched.
Only on analog channels
This gate wasn't in the first version:
if ((pipe != NULL) && (trxGetMode() == RADIO_MODE_ANALOG))
I applied the split blindly at first — every channel, both modes. On analog it was exactly what I wanted. On DMR it collided immediately: a digital channel is already spending its screen on talkgroup and contact lines, and a two-line name shoves all of that around.
I could have chased down every DMR layout interaction. Instead I asked what was actually true: the mod was already fully useful on analog, and analog is where my newcomer channels live anyway — MURS, GMRS, FRS, repeaters. So it ships analog-only, and the DMR problems stay unsolved instead of half-solved.
One detail so the same codeplug works everywhere: on a digital channel the pipe isn't drawn literally — it's rendered as a space. You name the channel once, and each mode does something sensible with it.
Picking the font, and the part I got wrong first
OpenGD77 has a genuinely wide font — 16 pixels across, 32 tall. It looks great and it doesn't always fit. The screen is 160 pixels wide, so that font gives you exactly ten characters per line:
wideName = (dblHeight && settingsIsOptionBitSet(BIT_UI_WIDE_NAME) &&
(longest <= (DISPLAY_SIZE_X / WIDE_CHAR_WIDTH)));
longest is whichever of the two lines is longer. If it fits,
both lines get the wide font. If it doesn't, the whole thing drops back to
the narrower font rather than rendering one line wide and one line small.
The reason that test has to exist: the draw call silently truncates anything too long. No error, no wrap — the end of your channel name just is not there. That cost us a little time before we measured it.
My first version hard-coded the narrow font for names without a pipe, which meant short single-line names could never get the big font even when they obviously fit.
It's a setting, not a fork
This rides on the existing Text size option rather than adding a new one:
- 1 — normal, stock behavior
- 2 — stock double-height
- 3 — the wide font, when the name fits
Anyone who doesn't want this leaves Text size at 1 and gets the stock radio back. That matters to me: I'm handing these radios to people, and I don't want the firmware to be a thing they're stuck with.
Centering two lines
The last piece is unglamorous arithmetic. The usable band between the header and the zone footer is 94 pixels tall, so two lines plus a six pixel gap get centered in it rather than pinned to a fixed row. That keeps the block looking deliberate at every font size.
The transmit timer had to move too
This is the part I didn't see coming. Key up and a transmit timer appears near the top of the screen — right where the channel name now lives. Stock firmware gets away with this: it shuffles its single-line name down a row to make room. But it knows nothing about my second line, so the timer simply drew on top of the name — overlapping text, the one thing you most want to read while transmitting.
So the timer is drawn on the zone footer row instead, which is otherwise idle during transmit:
/* was DISPLAY_Y_POS_TX_TIMER, up near the channel name */
int8_t yOverride = DISPLAY_Y_POS_ZONE;
snprintf(buffer, SCREEN_LINE_BUFFER_SIZE, "%d", txTimeSecs);
uiUtilityDisplayInformation(buffer, DISPLAY_INFO_TX_TIMER, yOverride);
With the timer gone from the top, the channel name no longer needs its transmit special case at all — it simply keeps the centered position it already had.
One exception. The DM1701 has a shorter screen and no spare footer row to give away, so it keeps the stock arrangement and still shifts the name down while transmitting. That's a compile-time guard rather than a setting.
This is why the timer change belongs to the split-name patch instead of being a mod of its own: without it, the two-line name doesn't survive a transmit.
Patches only. I don't hand out built firmware images — a large part of any flashable image belongs to the radio vendor. You bring your own OpenGD77 source and build it.