Мост к DMR-модулю, разбор спектра REFV DualTachyon, карта запчастей прошивки

Баузбенд FM100B:
- найден прозрачный мост ПК<->модуль (включение с зажатой МЕНЮ), проверен живьём
- расшифрована контрольная сумма кадров (one's complement, BE), сверена с ответом рации
- инструмент tools/fm100b.py (ping/send/raw/scan)
- cmd 0x25 = запрос версии, модуль отвечает V1.2.0.32 (совпало с офиц. образом)
- разобран диспетчер входящих кадров: 193 записи, реальный код у 10 команд
- cmd 0x59 = индикация приёма, она же управляет гейтом звука PA14
- исправлено: boot-handshake это cmd 0x84, а не 0x64 (research/re/dmr.md)

Спектроанализатор REFV DualTachyon (docs/refw-spectrum.md):
- вызывается как функция горячей клавиши №22 Analog Spectrum
- вход 0x08009CAA -> обычный 0x080139E4 / по зоне 0x08015318
- спектр это экран №11; тик 0x08013BA4 (автомат на 4 состояния), клавиши 0x08013BFC

Декомпозиция (docs/firmware-parts.md):
- два процессора + внешний SPI = три канала внедрения
- карта ресурсов SPI: шрифты, пиньинь, голос, таблица Unicode
- найден штатный загрузчик ресурсов FontVoicePicture (шрифты/голос/картинки)
- дерево меню целиком: MIC/SPK Gain, RX/TX Limit, SMS Format уже в стоке
- аудио двухступенчатое: PA2 питание УНЧ, PA14 гейт от DMR-модуля

Прочее:
- везде исправлен режим прошивки: тангента PTT вместо клавиши "*"
- устаревший Ru-4D_Flasher.exe удалён из репозитория
- добавлены инструменты реверса: xref, refs, gpiomap, gpioscan, schem
Этот коммит содержится в:
2026-07-22 21:17:20 +09:00
родитель ae36c3b729
Коммит 5f4d207aa5
34 изменённых файлов: 21718 добавлений и 17823 удалений
+4 -3
Просмотреть файл
@@ -3,7 +3,8 @@
it into a single Windows .exe with PyInstaller."""
import base64, os, subprocess, sys
ROOT = "C:/Users/vikto/Documents/Claude/rt-4d"
# project root = parent of this script's directory (portable)
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
FW = f"{ROOT}/stock-fw/rt4d_ru_full.bin"
DIST = f"{ROOT}/dist"
@@ -45,7 +46,7 @@ def do_flash(port_name, log, prog):
if not b: p.write(b"\xff")
elif b == b"\xff": ready = True; break
if not ready:
raise RuntimeError("Рация не отвечает. Выключите и включите её\nс зажатой клавишей * , затем повторите.")
raise RuntimeError("Рация не отвечает. Выключите и включите её\nс зажатой тангентой PTT, затем повторите.")
log("Бутлоадер найден. Стирание...")
for trig in (0x10, 0x55):
pl = bytes([0x39, 0x33, 0x05, trig]); pl += cksum(pl)
@@ -80,7 +81,7 @@ class App:
tk.Label(root, text="Ru-4D - Прошивка рации", font=("Segoe UI", 15, "bold"), **F).pack(pady=(16, 0))
tk.Label(root, text=INFO, font=("Segoe UI", 9), bg="#131a24", fg="#7f8ea3").pack()
steps = ("1. Выключите рацию.\n"
"2. Включите её, удерживая клавишу * (режим прошивки).\n"
"2. Включите её, удерживая тангенту PTT (режим прошивки).\n"
"3. Подключите рацию к ПК кабелем USB-C.\n"
"4. Выберите COM-порт и нажмите Прошить .\n"
"5. Не отключайте кабель до конца записи.")