Files
rt-4d/docs/tuning-software-protocol.md
T
viktorиClaude Opus 4.8 87df47cb94 Полный реверс протокола калибровки тюнера (IL-декомпиляция)
- research/tuning-re/cil_disasm.py — минимальный CIL-дизассемблер (dnfile).
- research/tuning-re/command-templates.txt — извлечённые шаблоны всех команд.
- docs/tuning-software-protocol.md: точная карта команд-полей + раскладка bufDigTune
  + ВЫВОД: частотная калибровка = ЗАМКНУТЫЙ ЦИКЛ (Set-команды несут band/опорные
  частоты, не абсолютное смещение; WriteAll данных не несёт). Слепой скрипт записи
  freq-трима может снова сбить калибровку -> безопаснее гнать штатным тулом с MMDVM
  BER вместо частотомера, либо сперва рид-онли снять текущую калибровку.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NikMGoqQWWk9wy2ww2vJAr
2026-07-24 03:39:59 +09:00

110 строки
7.9 KiB
Markdown
Исходник Ответственный История

Этот файл содержит неоднозначные символы Юникода
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Radio Tuning Software 241219 — реверс протокола калибровки
Декомпиляция `Radio Tuning Software 241219.exe` (dnfile). Сборка **`UV5118_4819_Tune`**
(«4819» = шина управления DMR-модулем `DIG-SCN/SDA/SCK4819` со схемы RT4DDLT01).
## Главное
Тюнер калибрует модуль **тем же 0x68-протоколом**, что и `tools/fm100b.py` (НЕ 0xAAAA, как
считалось раньше) — значит **достижимо через наш мост** (режим «Обновление DMR чипа»).
Формат кадра тот же: `68 cmd b sub CKhi CKlo lenHi lenLo <payload> 10`, CRC как в fm100b.py.
## Команды калибровки (0xB0–0xBD), извлечены из статических шаблонов (FieldRVA)
| cmd | назначение (по контексту UI/методов) | пример payload |
|------|--------------------------------------|----------------|
| 0xBD | Connect / вход в режим калибровки | `01` |
| 0xB0 | старт/стоп калибровки (on/off) | `01` / `00` |
| 0xB1 | таблица границ диапазонов (band, N, частоты ×N по 4Б BE, Гц) | UHF: 400.125/435.125/469.975 МГц; VHF: 136.125/150.125/174.125 МГц |
| 0xB2 | девиация/модуляция набор 1 (band, idx, val) | `01 01 80`; read: `00 02` |
| 0xB4 | девиация/модуляция набор 2 | `01 01 80`; read: `00 02` |
| 0xB6 | мощность/параметр (band, idx, val16?) | `01 01 01 96`; read: `00 01 00` |
| 0xB7 | частотные точки/оффсеты (band, idx, …) | `01 00 05 9a 01 08 75`; read: `00` |
| 0xB8 | мощность/параметр | `01 01 01 02 78`; read: `00 01 01 00` |
| 0xB3 | SQ/шум набор 1 | `01 01 02 02` |
| 0xB5 | SQ/шум набор 2 | `01 01 00 02` |
Первый байт payload = **band**: `01`=UHF, `02`=VHF (в 0xB1); в set-командах `01`=UHF-set,
`00`=read/VHF. Частоты в 0xB1 — 32-битные BE в Гц.
## Модель калибровки (из UI-методов и дефолтов)
- Панель делит диапазон на **15 частотных точек** (методы `cboxNN_1..15`, `nPowerH/L_1..15`,
`nSQN/W_1..15`, `nNoiseN/W_1..15`) — для каждой точки свои: мощность H/M/L, девиация (Mod1..3),
SQ, шумоподавление.
- Отдельно `num_U_DigFreq` / `num_V_DigFreq`**смещение ЦИФРОВОЙ (DMR) частоты** UHF/VHF
(наш параметр!), `num_U_AnaFreq` — аналоговой. Плюс `chbox_U_DigFreq` (вкл).
- Кнопки: `btnCal_U_Freq` (автокалибровка частоты по прибору), `btnRead_U_Freq`,
`btnStop_U_Freq`; `btnRead_U_Mod/PWR`, `btnCal_U_Mod/PWR`; `btnTouchuan` = 透传 (прозрачный
режим TX для замера). `ButtonRead`/`btnWriteAll`/`ButtonWrite`; `SaveTuneData`/`SaveDigTuneData`
= запись+сохранение (это и есть «Finish»).
- Приём/разбор ответов: `Port_DataReceived``RecvDataOperation` (≈74 обработчика по cmd),
`DataSum` = контрольная сумма.
## Заводские дефолты (из блоба)
```
mod: b9 b9 b9 b9 b9 b9 (6×) # девиация-дефолт
32 32 32 32 32 32
9b 9b 9b 9b 9b 9b
flags 00 ff 00
37 a0 38 6b 40 ab # ?
06 02 06 02 0a 00 05 00
15pt: 3a 3c 3f 41 44 47 4a 4b 4c 4d 4e 4f 50 51 52 # 15 частотных точек (растущие)
80 00 80
12 e2 34 40 2a 4f b3 (×2)
```
## Точная карта команд-полей (из .ctor через InitializeArray) — ПОДТВЕРЖДЕНО
Транспорт: **115200 8N1**, ответы 9 или 12 байт (`ReceivedBytesThreshold`). CK-поле `00 00`
в шаблонах и НЕ пересчитывается → **модуль не проверяет CRC для cal-команд**.
Управление мостом (кадр `34 52 05 <cmd> <ck>` — к AT32, не к модулю):
```
CmdConnect 34 52 05 10 9b # войти в cal-мост
CmdEnd 34 52 05 ee 79 # выход
CmdTCOn 34 52 05 54 df #透传 (прозрачный TX) UHF
CmdTCOn_V 34 52 05 58 e3 # прозрачный TX VHF
```
Калибровка (0x68 → модуль):
```
CmdOpenCal 68 b0 01 01 00 00 00 01 01 10 # 0xB0 payload 01 — открыть cal
CmdColseCal 68 b0 01 01 00 00 00 01 00 10 # 0xB0 payload 00 — закрыть
CmdWriteAll 68 bd 01 01 00 00 00 01 01 10 # 0xBD — сохранить cal в NV (БЕЗ данных!)
SetCalFreq_U 68 b1 ...01 01 03 <400.125M×2><435.125M×2><469.975M×2> 10 # опорные UHF (BE Гц)
SetCalFreq_V 68 b1 ...01 02 03 <136.125M×2><150.125M×2><174.125M×2> 10 # опорные VHF
SetAnaTX 68 b3 ...01 01 02 02 10 # рантайм патч [8..11]=01 01 02 02
SetDigTX 68 b5 ...01 01 00 02 10 # рантайм: [8]=1 [9]=1 [10]=DetectDevice [11]=2
SetAnaVCCN 68 b2 ...01 01 80 10
SetDigVCCN 68 b4 ...01 01 80 10
SetCalPWR 68 b8 ...01 01 01 02 78 10
SetCalMod 68 b6 ...01 01 01 96 10 # девиация, дефолт 0x96=150
SetCalSlot 68 b7 ...01 00 05 9a 01 08 75 10
Read*: ReadAnaVCCN 68 b2..00 02 | ReadDigVCCN 68 b4..00 02 | ReadMod 68 b6..00 01 00
ReadPWR 68 b8..00 01 01 00 | ReadSlot 68 b7..00
```
## Раскладка bufDigTune (частотные трим-значения, из Save/ReadDigDataToUI)
```
[0]=устройство(cboxDevice) [1]=V_DigFreq [2]=U_AnaFreq [3]=V_AnaFreq [4]=U_DigFreq
дефолты bufDigTuneInit = 01 00 00 00 00 b9×6 32×6 9b×6 → все трим-смещения по умолчанию 0
```
Трим — **однобайтовый знаковый** (0 = центр). `num_U_DigFreq ↔ track_U_DigFreq`.
## ⚠️ ВАЖНО: частотная калибровка — ЗАМКНУТЫЙ ЦИКЛ (нужен частотомер)
Реверс `RecvDataOperation`: Set-команды несут band/DetectDevice и опорные частоты, но **НЕ
абсолютное смещение**; `CmdWriteAll` payload не несёт. Т.е. штатная калибровка: `CmdOpenCal`
модуль ПЕРЕДАЁТ несущую → оператор смотрит частотомер/SDR и крутит `num_U_DigFreq` → модуль
подстраивается → `CmdWriteAll` фиксирует. Без прибора абсолютное значение не выставить «в одну
команду», а слепой скрипт записи МОЖЕТ СНОВА СБИТЬ калибровку.
**Вывод по путям:**
- Безопасно: гонять калибровку ШТАТНЫМ тулом (правильные кадры), MMDVM BER — вместо частотомера
(перебор `num_U_DigFreq` → WriteAll → PTT → BER). Уточнить, пишет ли ручной num+WriteAll трим
в NV модуля (WriteAll данных не несёт — возможно, только auto-cal реально пишет частоту).
- Скрипт: сначала РИД-онли реплицировать Connect+Read и снять текущую калибровку, потом решать.
Cлепую запись freq-трима НЕ слать.
## План применения (см. dmr-tx-recovery.md, путь через 0x68)
Вариант A (штатный тул): пользователь открывает Tuning SW → Read → крутит `num_U_DigFreq`
WriteAll → Save → сменить канал → PTT → BER на MMDVM. Перебор до минимума BER (без прибора).
Вариант B (скрипт): дореверсить cmd DigFreq → `tools/` слать 0xB7/0xBx через мост, MMDVM-фидбек.