FM100B = Sicomm SCT3258TD (документирован); Talker Alias, агент, SPI-инструменты, восстановление TX

Главное:
- Опознан DMR-чип: FM100B = Sicomm SCT3258TD. Датащит Packet Interface (126 стр) в docs/.
  Открывает калибровку/AMBE/вокодер по документации. Родня: UV-4R, китайские клоны.

Реализовано:
- Приём Talker Alias (cmd 0x60) — позывной крупно на экране (build_ta.py)
- Интерактивный агент — управление FM100B по COM без перешивки (build_agent.py + agent.py)
- Полная карта команд FM100B с живой рации (fm100b-commands.md)
- Работа с SPI: чтение/запись/восстановление codeplug и калибровки (spi_read/spi_wr/spi_restore)
- Конструктор дисплея + редактор прошивки (tools/display-editor)

Документация:
- docs/SCT3258_packet_interface.txt/.pdf — спека DMR-чипа
- docs/fm100b-commands.md — карта команд
- docs/dmr-tx-recovery.md — диагноз/восстановление DMR-передачи

Инструменты: flash_ps.py (прошивка через WSL/powershell), sniff.py (снифер кадров),
hotspot_rxoffset_sweep.py, apply_patch.py, build_* сборщики.

Важно: DMR TX-калибровка сбита в экспериментах со SET-командами модулю; восстановление
через offset-компенсацию / .updat Radtel / калибровку по прибору (docs/dmr-tx-recovery.md).
Этот коммит содержится в:
2026-07-24 02:52:51 +09:00
родитель 5f4d207aa5
Коммит 6d49ba3cba
21 изменённых файлов: 11662 добавлений и 0 удалений
Двоичные данные
Двоичный файл не отображается.
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+54
Просмотреть файл
@@ -0,0 +1,54 @@
# RT-4D: DMR не передаёт на хотспот — диагноз и восстановление
## Симптом
DMR-приём работает (рация принимает из хотспота), **DMR-передача не декодируется хотспотом**
(в логе MMDVMHost 0 «received RF», MMDVMCal рацию не видит). Аналог RX/TX работает.
Модуль отвечает в мосте, версия V1.2.0.32. Проблема одинакова на стоке и REFV.
## Корень (подтверждён реверсом + техподдержкой Radtel)
**TX-частота рации смещена > ±0.2 кГц** от номинала. По Q&A Radtel даже ±0.2 кГц не даёт
хотспоту синхронизироваться с передачей. Приём работает, т.к. RX-смещение в допуске.
Причина смещения: заводская частотная калибровка была сброшена/затёрта, а **Radio Tuning
Software «Write» залил ДЕФОЛТНЫЕ** значения смещения — неточные для конкретного экземпляра.
### Где что лежит
- **Калибровка ОСНОВНОГО тракта рации** — SPI region 0x40 (0x000000, 4 КБ). Восстановлена
из `radio-spi-dump.bin`**приём заработал**. Весь codeplug тоже восстановлен из дампа.
- **Частотная калибровка / DMR-девиация** — в NVRAM модуля FM100B. Команды модуля:
`SPCali_FreqOpt`, `SPCali_DigMod` (цифр. модуляция), `SPCali_PowerOpt`, `ATC_RfDeviation_SetReq`.
Перепрошивка кода модуля их НЕ трогает; сток при старте их НЕ шлёт → сброшенное значение держится.
### Radio Tuning Software — как устроена (reverse .NET)
- Работает через **прозрачный мост** (режим МЕНЮ), маркер кадров `0xAAAA`,
команды `CmdConnect / CmdOpenCal / CmdWriteAll / CmdEnd`.
- Калибровка = **15 частотных смещений** `nOffset_1..15` + `num_U/V_DigFreq` (DMR-частота UHF/VHF).
- Кнопки: `Read` (с рации в UI), `Write/WriteAll` (в рацию), `Save``.updat` файл.
- **ВАЖНО:** по Q&A Radtel после калибровки жать «Finish» (сохранение). Возможно Write без
этого не фиксирует. И для точной калибровки нужен **прибор** (SDR/частотомер) — крутить
offset до ±0.2 кГц.
## Пути восстановления (по приоритету)
1. **Компенсация на хотспоте (RXOffset)** — БЕЗ прибора. Если TX рации смещена на постоянный
X Гц, выставить на хотспоте `RXOffset` так, чтобы приёмник поймал смещённую передачу.
Перебор RXOffset в MMDVM.ini (±1000 Гц шагом ~100), рестарт MMDVMHost, при передаче рации
(PTT) искать «received RF» в логе. Требует, чтобы владелец жал PTT в момент перебора.
Инструмент: `tools/hotspot_rxoffset_sweep.py` (готовится).
2. **Точная калибровка частоты по прибору** — Radio Tuning Software + SDR/частотомер:
Read → крутить `num_U_DigFreq`/`nOffset` до ±0.2 кГц по прибору → **Finish/Save + WriteAll**.
3. **Заводской `.updat`** — запросить у Radtel техподдержки файл калибровки для серийника,
либо debug-софт. Тогда Radio Tuning: Open `.updat` → WriteAll.
## Что уже сделано
- ✅ SPI-калибровка рации (region 0x40) восстановлена из эталона → приём работает.
- ✅ Весь codeplug (каналы/зоны/контакты/группы/ключи/лог/SMS/FM) восстановлен из `radio-spi-dump.bin`.
- ✅ Диагноз локализован: TX-частотное смещение модуля.
- ⏳ Осталось: вернуть точное TX-смещение (пути 1–3 выше).
## Инструменты
- `tools/spi_read.py` / `tools/spi_wr.py` — чтение/запись SPI через CPS (WSL powershell).
- `tools/fm100b.py` — команды модулю через мост (режим МЕНЮ).
- `tools/agent.py` — интерактивный агент (обычный режим).
+57
Просмотреть файл
@@ -0,0 +1,57 @@
# FM100B — карта команд (снята интерактивным агентом)
Снято `tools/agent.py` на прошивке `rt4d_agent.bin` — запрос каждой команды пустым
payload (`68 cmd 01 01 CK CK 00 00 10`), ответ модуля через снифер. Рация V1.2.0.32.
`status` (байт [3] ответа): **0x00** = OK/есть данные, **0x01** = не поддержано или нужен payload.
## Отвечают данными (status 0x00, len>0)
| cmd | len | ответ | смысл |
|---|---|---|---|
| `0x04` | 1 | `03` | параметр |
| `0x24` | 4 | `01 00 40 01` | возможности/идентификатор модуля |
| `0x25` | 4 | `01 02 00 32` | **версия прошивки = V1.2.0.32** |
| `0x27` | 1 | `00` | статус |
| `0x28` | 1 | `00` | статус |
| `0x34` | 2 | `00 00` | параметр (2 байта) |
| **`0x35`** | 35 | `10 02 21 6a df 62 e1 4f 53 90 38 …` | **таблица** (записи с сигнатурой `e1 4f 53 90`) |
| `0x36` | 1 | `00` | статус |
| `0x3B` | 1 | `01` | флаг |
| **`0x43`** | 33 | `10 01 01 70 65 57 5b e1 4f 53 90 31 … 32 …` | **таблица**: две записи `…e1 4f 53 90` + индекс 1/2 (контакты/RX-группы?) |
| `0x46` | 1 | `00` | статус |
| `0x85` | 1 | `00` | статус |
## Приняты без данных (status 0x00, len 0) — действия/OK
`0x01 0x03 0x1A 0x40 0x4B 0x65 0x66`
(`0x66` = девиация ш/у полосы по changelog; `0x65` рядом — вероятно связанное)
## Не поддержано / нужен payload (status 0x01)
`0x0D 0x0E 0x10-0x19 0x22 0x2B 0x2C 0x2D 0x30 0x37 0x3A 0x3C 0x3D 0x3F 0x41 0x44 0x45
0x47 0x4A 0x4E 0x4F 0x50 0x51 0x52 0x54 0x56 0x58 0x5C 0x5D 0x5E 0x60 0x61 0x63 0x64
0x67 0x83 0x84 0x86 0x87`
(это SET/enable-команды — на пустой запрос отвечают отказом; проверять с payload)
## Не опрошены (опасные SET — меняют состояние)
`0x05` конфиг канала · `0x06` вызов · `0x07` данные канала · `0x0A` PTT ·
`0x49` свой DMR ID · `0x62` параметры вызова · `0x81/0x82` SMS · `0x2A 0x42 0x48
0x4C 0x4D 0x55 0x57` · **`0x3E` прошивка модуля — НЕ СЛАТЬ**
## Известны из снифера входящего вызова (FM100B → MCU)
| cmd | смысл |
|---|---|
| `0x62` | параметры вызова (src/dst/TG) |
| `0x06` | setup (sub 0x60) / end (sub 0x6f) |
| `0x60` | **Talker Alias (позывной)** — см. docs/talker-alias |
| `0x59` | активность приёма (гейт звука PA14) |
| `0x05` | конфигурация канала |
## Открыто
- **AMBE-выдача** (для модема): по умолчанию нет. Кандидаты — SET-команды со `status 0x01`,
проверять с payload `enable` + активный вызов + наблюдение потока через агента.
- Таблицы `0x35`/`0x43`: расшифровать формат записи (сигнатура `e1 4f 53 90`).