Firmware Internals
This section documents the internal architecture of the RS-UV3 V2.4a firmware, derived from reverse engineering the original HEX file using Ghidra and gputils.
Firmware Overview
Section titled “Firmware Overview”| Property | Value |
|---|---|
| Version | 2.4a |
| MCU | PIC18F46J11-I/PT |
| Package | TQFP-44 |
| Flash | 64KB (36,296 bytes used) |
| RAM | 3,776 bytes |
| Clock | Internal oscillator, 8 MHz |
| Voltage | 3.3V |
The firmware handles:
- Serial command parsing (66 commands across two dispatchers)
- I2C communication with the RDA1846S transceiver chip
- EEPROM storage for channel memories and configuration
- CTCSS/DCS tone encoding and decoding
- CW and DTMF generation
- Beacon timing and transmission
Architecture
Section titled “Architecture”┌─────────────────────────────────────────────────────────────┐│ Main Loop (0x000400) ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ ││ │ Check UART │→ │ Parse Cmd │→ │ Dispatch A or B │ ││ │ RX Buffer │ │ 2-char code │ │ based on 1st char │ ││ └─────────────┘ └─────────────┘ └─────────────────────┘ │└─────────────────────────────────────────────────────────────┘ │ ┌───────────────┴───────────────┐ ▼ ▼┌──────────────────────────┐ ┌──────────────────────────┐│ Dispatcher A (0x0042b0) │ │ Dispatcher B (0x005972) ││ 5,826 bytes │ │ 10,632 bytes ││ ────────────────────────│ │ ────────────────────────││ PD, PW, RC, RR, RS │ │ AF, AI, AO, B1, B2... ││ ST, CP, FD, BL │ │ (bulk of commands) │└──────────────────────────┘ └──────────────────────────┘ │ │ └───────────────┬───────────────┘ ▼ ┌──────────────────────────────┐ │ Hardware Abstraction Layer │ │ ─────────────────────────── │ │ • I2C to RDA1846S (synth) │ │ • EEPROM read/write │ │ • UART TX/RX │ │ • ADC for RSSI, temp, volts │ └──────────────────────────────┘Memory Layout
Section titled “Memory Layout”| Region | Address | Size | Purpose |
|---|---|---|---|
| Reset vector | 0x000000 | 4B | Jump to init |
| High-priority ISR | 0x000008 | 16B | Serial RX entry |
| Low-priority ISR | 0x000018 | 874B | Timers, buffers |
| Init + Main | 0x000400 | 2,098B | Setup and event loop |
| Dispatcher A | 0x0042b0 | 5,826B | Memory/power commands |
| Dispatcher B | 0x005972 | 10,632B | Radio config commands |
| String tables | 0x008B38 | ~1,800B | Response strings |
| Total code | — | 36,296B | 55% of 64KB flash |
Tools Used
Section titled “Tools Used”The reverse engineering was performed with:
| Tool | Version | Purpose |
|---|---|---|
| Ghidra | 12.0.1 | PIC-18 decompilation, cross-reference analysis |
| GhydraMCP | — | Ghidra integration for Claude Code |
| gputils | 1.5.2 | gpdasm disassembly, gpasm reassembly |
| objcopy | 2.45.1 | Intel HEX to raw binary conversion |
| Python 3 | — | Annotation scripts (annotate.py, c-port.py) |
Verification
Section titled “Verification”All reverse-engineered assembly was verified byte-identical to the original firmware:
# Convert both to raw binary and compareobjcopy -I ihex -O binary reassembled.hex /tmp/verify.bincmp original.bin /tmp/verify.bin# Output: (no output = identical)This verification runs automatically via make verify in the source directory.
Section Contents
Section titled “Section Contents”- Command Dispatch — How the firmware parses and routes serial commands
- Memory Map — RAM variables, EEPROM layout, and register definitions
- I2C & Synthesizer — Communication with the RDA1846S transceiver chip
- Source Files — Annotated assembly, C port, and analysis tools