Add a 'Managing channels on the radio' section and a feature bullet for channel
create/delete. Update the screen-dim levels (now includes 15%) and drop the
'faintly-lit inactive segments' note (inactive 7-seg segments are now off).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add delete_channel and keep_one_channel to the language table (after mute) and
fill all 20 language files (13 translated, English fallback for the rest), with
correct single-byte ISO-8859 accents. Wire them into the Delete Channel label,
confirmation and last-channel guard. The new strings land on empty voice-table
slots, so they play as silence (no crash, no .vpr regeneration).
flash.sh now always rebuilds the .gla language packs so edits to the language
files are actually picked up (previously a stale pack was re-flashed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add two codeplug primitives - codeplugAllChannelsIndexSetUnused() (frees a
channel slot: clears the in-use bitmap bit, persists the header, fixes counts)
and codeplugZoneRemoveChannelFromZoneAndSave() (removes a channel from a zone's
list) - and wire two new Channel quick-menu items:
- 'new channel': allocates the first free slot, writes a blank 145.500 FM
channel, adds it to the current zone, reloads the zone and opens Channel
Details to edit it.
- 'Delete Channel': confirmation, then scrubs the channel from every real zone
before freeing the slot. Guards against deleting the last channel and honours
the read-only/APRS lock.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Flag any release with major version 0 as a Forgejo pre-release on create, and
PATCH the flag on re-runs so it stays correct. Existing v0.1.0/v0.2.0/v0.3.0
releases were updated to pre-release too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The menu label 'Screen Dim' is a raw literal, and the shared menu code voices
labels through voicePromptsAppendLanguageString(), which derives the prompt
index from the pointer's offset within the language table and crashed on a
foreign pointer (v0.2.0 fixed only the value, not the label). That helper now
ignores pointers outside the language table.
Bump version to 0.3.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Screen Dim passed a plain literal ('100%'/'50%'/...) to
voicePromptsAppendLanguageString(), which derives the prompt index from the
string's offset within the language table; a foreign pointer produced a garbage
index and crashed (only with voice on). Route the value through
voicePromptsAppendString() instead. Also move the 3-bit dim level's high bit off
legacy option bit 2 to bit 29 and clamp the level against the option arrays.
Bump version to 0.2.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Inactive segments now render in the background colour (off) instead of dimmed.
- The 7-seg renderer left the foreground on the last segment drawn (now the
background colour), which hid MHz; re-apply the frequency theme colour before
drawing MHz so it reappears and matches the digits.
- Move the TX frequency line down 1px for a little more RX/TX separation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add SCREEN_DIM_15 (Off / 100 / 50 / 30 / 15). The value now needs 3 bits, so
repurpose the spare BIT_UNUSED_2 as BIT_SCREEN_DIM_2; existing codeplugs (bit 2
clear) keep their level, no reset.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- README: add 'What's different from OpenGD77' (incl. the new SK2 mute) and a
dedicated 'Flashing' section (DFU steps, per-model flash.sh, donor note).
- scripts/forgejo-release.sh: build/attach a single platform or all, reuse an
existing release, replace same-named assets, and warn if freetrxVersion.h
doesn't match the tag.
- TOOLS.md: document the platform build argument.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
./build-firmware.sh DM1701 builds OpenDM1701.bin with PLATFORM_RT84_DM1701 +
PLATFORM_VARIANT_DM1701 (vs PLATFORM_MDUV380). Same firmware source, same GCC 14
toolchain and codec placement. Not officially tested on DM-1701 hardware yet.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- New freetrxVersion.h with semver (MAJOR/MINOR/PATCH + string), currently 0.1.0.
- Firmware Info top line now shows "FreeTRX v0.1.0"; the git commit ID line is
unchanged. The version is also announced via voice prompt.
- CHANGELOG: promote the accumulated changes to a 0.1.0 section.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Splash screen and Firmware Info name now show "FreeTRX".
- Firmware-info credits: "Marcus DK1DA", a separator, and a thank-you to the
original OpenGD77 authors.
- README documents that this iteration is developed/tested only on the TYT
MD-UV380 and Retevis RT-3S, with a contact for testing other supported radios.
- CHANGELOG updated.
Hardware/tooling identifiers (build filename, MD-UV380 model IDs, hotspot
version string) intentionally left unchanged to avoid breaking flashing and
Pi-Star/MMDVM compatibility.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Rename the project to FreeTRX (fork of OpenGD77).
- New README.md documenting the fork and its upstream source
(OpenGD77 R20260131 / OpenGD77_MDUV380_DM1701_20260130).
- Preserve the original project README as README.OpenGD77.md.
- Add LICENSE.md reproducing the inherited OpenGD77 license (modified
BSD 3-Clause + non-commercial clause). The license is NOT GPL-compatible and
cannot be relicensed; all original copyrights are retained.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the built-in strike-through over the FM/DMR mode text when muted; the
header "M" (and red LED flash) are the mute indicators now.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Treat the volume control at its minimum (lastVolume == -99, the firmware's
'muted' position) as effectively muted, so the red LED flash, the header M
and the built-in strike-through appear without an explicit SK2 mute.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The private-call caller ID was drawn at a hardcoded y=16, which now collides
with the S-meter label row. Use DISPLAY_Y_POS_CONTACT (same as the group-call
contact line) so it clears the labels.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a one-tap audio mute on the VFO and Channel screens:
- SK2 short-tap toggles mute via the built-in audioAmpMute()/audioAmpIsMuted().
The tap is only consumed by the existing "set TX TG to incoming" behaviour
while a DMR QSO is on screen, so mute works everywhere else.
- Header: a bold "M" is shown just left of the battery while muted (the
firmware's built-in strike-through over the mode text also still shows).
- LED: flashes red for 0.5s every 2s while muted (main loop), overriding the
normal RX/TX LED.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump DISPLAY_MAIN_CONTENT_TOP_PAD 4 -> 8 so the DMR RX talkgroup/talker (and the
FM contact / CTCSS / squelch info sharing that strip) no longer crowds the S-meter
label row. Contact moves from y=28 to y=32, leaving a clear gap below the labels.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render the VFO/Channel frequency (and the SK1-held frequency view, which share
uiUtilityDisplayFrequency) as 7-segment "LED" digits instead of the normal font,
on colour displays.
- HX8353E_display.c: displayDrawFrequencySevenSeg() draws each digit's 7 segments
as filled rectangles; lit segments use the theme frequency colour, inactive
segments a dimmed (~3/8 intensity, same hue) version, giving the classic LED
look with faintly-visible "off" segments. The decimal point takes half a cell.
- Digits are 12 px wide (wider than the 8 px font) to fill the space toward the
"MHz" label; height follows the existing single/double-height frequency layout.
- Monochrome displays keep the normal font.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gd-77_screen_grabber.py is the universal OpenGD77 screen grabber (despite the
name): it talks over the USB CDC serial port, auto-detects the radio model and
reads the MD-UV380's 160x128 RGB565 framebuffer, saving a PNG. Handy for
capturing UI changes. gd-77_firmware_loader.py is the GD-77 (MK22) SGL loader,
included for completeness (the MD-UV380 uses opengd77_stm32_firmware_loader.py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an optional "Screen Dim" setting (Display Options) that, in Auto backlight
mode, dims the screen to a fraction of the configured brightness after the
backlight timeout instead of going to the off level. Any activity restores full
brightness.
- Setting values: Off / 100% / 50% / 30%, stored in two spare option bits
(no settingsStruct change, no version bump; existing codeplugs default to Off).
- display.c: displayGetIdleBacklightPercentage() computes the idle level.
- applicationMain.c: the idle-timeout tick dims to that level; an incoming
signal (hasSignal) re-triggers full brightness so RX keeps the screen lit.
TX already forces full brightness.
- menuDisplayOptions.c: new entry with a hardcoded English label (no language
files touched).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Shift the contact/TG, CTCSS/DCS and squelch info lines down by a tunable
DISPLAY_MAIN_CONTENT_TOP_PAD (4px) on MD-UV380/DM1701, so they no longer sit
flush against the new S-meter label row. Frequency and everything below are
unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rework the header RSSI bar (uiUtilityDrawRSSIBarGraph) from a solid two-stage
bar into discrete blocks, one per S-level, on colour displays:
- 9 green blocks for S1..S9 (4 dB per S-unit) plus 6 red blocks for the S9+
region (10 dB per block, S9+10..S9+60), drawn with 2 px gaps so the header
background shows between them.
- Proportional fill: full blocks below the level, leading block partially filled
to reflect the exact signal.
- Bar height raised 4 -> 6 px; the FM/DMR mic-level bars follow the same height
so nothing is left behind when switching RX <-> TX.
- Scale labels below the blocks: S1/S3/S5/S7/S9 under the green zone and
+20/+40/+60 under the red, centred under their blocks (font_6x8). The label
row is blanked while transmitting.
Monochrome displays keep the original solid bar. Existing analog S9+ RSSI
compression is preserved, so calibration is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The radio hard-froze (needs battery pull) the instant it processed an incoming
DMR frame — repeater reply, or noise on a DMR channel. FM and DMR TX-without-a-
listening-repeater were fine. Cause: codec_interface.c invoked the AMBE codec
through hand-written inline assembler with no operands and no clobber list,
branching (BL) to an absolute address. That code's correctness depends entirely
on a specific compiler's register allocation; modern GNU toolchains (both ARM
GCC 10 and 14) miscompile it, corrupting state on the first codec call.
Port the official R20260504 (git ebd7100) rework: replace all five inline-asm
calls (2x decode, 2x encode, 1x ECC) with C function-pointer calls. Each call
reproduces the exact register/stack layout the assembler set up (AAPCS: args
1-4 -> r0-r3, args 5+ -> stack) and sets the Thumb bit on the target address.
Also drop the trailing semicolons from the AMBE_* address macros in codec.h so
they can be used in C expressions.
Builds cleanly with the GCC 14.2 Docker toolchain (no STM32CubeIDE needed) and
DMR RX/TX now works on the radio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring the headless Docker build closer to the official OpenGD77 build and
add a flashing helper.
docker/Dockerfile
- Replace Ubuntu's stock gcc-arm-none-eabi (GCC 10.3.1) with the Arm GNU
Toolchain 14.2.rel1 (GCC 14). The official firmware is built with GCC 14
(gnu-tools-for-stm32 14.3); GCC 10 produced a firmware that hard-faults on
the DMR path. Guard the image build to fail if the compiler is not GCC 14.
- git config --system safe.directory '*' so the build stamps a real GitID
instead of #UNKNOWN.
docker/build.sh
- rm -rf build before compiling. obj/ lives on the host mount and was being
reused across toolchain changes, silently relinking stale .o files (an
earlier rebuild produced a byte-identical GCC-10 image because of this).
docker/firmware.mk
- Add -DNDEBUG to exactly mirror the STM32CubeIDE "MDUV380_FW" release config
(which defines both NDEBUG and DEBUG).
flash.sh
- Helper to flash via opengd77_stm32_firmware_loader.py with model, secondary
language (auto-builds the .gla files) and the DMR codec donor.
.gitignore
- Ignore generated *.gla files and the host-side languages_builder binary.
Note: the GCC 14 rebuild did NOT resolve the DMR-receive hang; that fault is in
the firmware source revision (this tree is a snapshot; the known-good build is
commit ebd7100, not present here) and is out of scope of these build changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>