- 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
110 строки
7.9 KiB
Markdown
110 строки
7.9 KiB
Markdown
# 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-фидбек.
|