# Спектроанализатор REFV (DualTachyon) — где он лежит Разбор по образу `refw/rt-4d-refw-beta42.bin` (251 904 Б, md5 `c6ab8306b5512b21b1f49fda8df2b1f5`, база загрузки `0x08002800`). Именно эту реализацию хвалят пользователи. Ниже — как до неё добраться и из чего она состоит. --- ## 1. Как спектр вызывается Спектр **не является пунктом меню**. Это **функция назначаемой клавиши № 22** — `Analog Spectrum` в списке функций горячих клавиш (`0x080213A9`, записи по 16 байт). > В стоке та же функция есть под номером **21** — REFV сдвинул нумерацию, вставив > `Bandwidth Toggle` на позицию 15. Диспетчер функций клавиш: **`TBH @0x080094EC`**, 45 ветвей (`cmp #44` перед таблицей), таблица с `0x080094F0`. Ветка 22 → **`0x08009CAA`**. ## 2. Точка входа `0x08009CAA` ```c if (mode == 3 || mode == 4) return; // в этих режимах спектр запрещён bl 0x08010ADC; // подготовка // [area*5 + 0x84] — режим области: // 0=Frequency, 1=Channel, 2=Zone if (area_mode == 2) bl 0x08015318; // ← спектр ПО ЗОНЕ else bl 0x080139E4; // ← ОБЫЧНЫЙ спектр goto 0x08009BC0; // общий выход ``` Это ровно совпадает с официальным описанием REFV: «переключитесь в режим VFO или канала, если нужен обычный спектр; из зоны он сканирует эту зону». ## 3. Обычный спектр — `0x080139E4` (инициализация) ``` 0x080139E4 push {r4-r8,lr} 0x080139E8 bl 0x08014888 ; подготовка подсистемы ... ; сброс флагов состояния 0x08013A2C mla r2, #0x30, chan, r3 ; запись канала = 48 байт 0x08013A30 ldr [r2+5] -> [r4+5] ; копирование частоты RX/TX 0x08013A38 ldr [r2+9] -> [r4+9] ; в рабочий VFO ... ; полоса/режим: bfi в [r4], [r4+4], [r4+0xe] 0x08013A86 bl 0x08011164 ; применить настройки ВЧ-тракта 0x08013AA6 bl 0x080136EC ; подготовка экрана 0x08013ABA bl 0x08013944 ; отрисовка шапки 0x08013AC8 bl 0x08015978 ; печать числа (r1=2 разряда) 0x08013AF8 ite eq / 'W' : 'N' ; метка полосы Wide/Narrow 0x08013B1C bl 0x0801C62C ; запуск 0x08013B22 movs r2,#0x0B 0x08013B24 strb r2,[0x200009B0] ; ← ЭКРАН = 11 0x08013B26 pop ``` **Ключевой вывод: спектр — это экран № 11.** Архитектура та же, что в стоке (`g_screen`, значения 0…11), только переменная в REFV живёт по адресу **`0x200009B0`**. ## 4. Модуль спектра целиком | Адрес | Роль | |---|---| | `0x08009CAA` | точка входа с горячей клавиши, выбор обычный/зонный | | **`0x080139E4`** | **инициализация обычного спектра**, ставит `экран = 11` | | **`0x08013BA4`** | **тик**: автомат на 4 состояния, счётчик `[база+0x3E] & 3` | | **`0x08013BFC`** | **обработчик клавиш** спектра, `cmp r0,#0x10` + `TBH @0x08013C20` (17 клавиш) | | `0x08013598` | шаг развёртки (состояние 1) | | `0x08012FA0` | рабочий обработчик (состояния 2 и 3) | | `0x0801307C` | ветка при `состояние > 1` | | `0x080135E8` | помощник (вызывается из `0x0801449C`) | | `0x080136EC`, `0x08013944`, `0x08015978` | подготовка экрана, шапка, печать чисел | | `0x08014888` | инициализация подсистемы | | **`0x08015318`** | **спектр по зоне** — отдельная реализация | ### Автомат тика `0x08013BA4` ```c state = (state + 1) & 3; // [база+0x3E] switch (state) { case 1: flags[1]=flags[2]=0; bl 0x08013598; break; // шаг развёртки case 2: flag=0; goto 0x08012FA0; // обработка case 3: flag=1; goto 0x08012FA0; default: goto 0x0800A57C; // пометить перерисовку } ``` Развёртка размазана по тикам главного цикла — экран не блокируется, поэтому спектр и ощущается отзывчивым. ### Спектр по зоне `0x08015318` Перебирает **200 каналов** зоны (`cmp r6,#0xC8`), запись зоны — **0x1BD байт**: ```c for (i = 0; i < 200; i++) { ch = zone[i].channel; // halfword, отбрасывается если >= 0x400 if (!(zone.scanlist_bitmap[i>>3] >> (i&7) & 1)) continue; // битовая карта scan-list read_channel(sp, 0x30*ch + 0x4000); // запись канала 48 байт из SPI // разбор полей: частота ubfx(…,8,12), CTCSS, полоса, режим // укладка в массив с шагом 28 байт } ``` Отсюда и фича «зонный спектр показывает живую информацию о субтонах». ## 5. Прочие детали - **Перерисовка**: `0x0800A5FC` — `TBB` на 12 экранов (`cmp #0x0B`), каждая ветка делает `memset(флаги_экрана, 1, N)`. Для экрана 11 — 16 элементов по адресу `0x200000A9`. - **Идиом связки экранов** встречается в 6 местах: `if (screen == 11 || (prev == 11 && (screen & ~4) == 8))` — экраны 8 и 12 накладываются поверх спектра (меню/подсказки). ## 6. Что даёт REFV сверх стока (полная таблица UI, 338 записей) Новые функции горячих клавиш: `Bandwidth Toggle`, `Talker Alias`, `RX AM/FM/**SSB** SW`, `DMR DCDM Switch`, `DMR TS/CC Switch`, `DMR Key Select`, `Next Zone`, `DTMF List`, `Freq Monitor`, `Last Call Info`, `Address Book`, `Contacts List`. Новое в меню: верхнеуровневое **`Extra`**, `Extra hotkey` + `0…9 Hotkey`, `Edit Scan List` в зонах, `SMS Templates`, `Time Calibrate`, `AM/FM/SSB RX` в канале, `Last Channel`, `Skip Scan`, `Radio Info`, `Flash Type`. ## 7. Как это перенести к нам Прямой перенос бинарного кода невозможен — REFV написан с нуля, у него своя карта памяти и свои структуры (запись канала 48 Б, запись зоны 0x1BD Б, экран в `0x200009B0`). Переносится **архитектура**: 1. Спектр — отдельный экран в общей диспетчеризации, а не модальный цикл. 2. Развёртка разбита на состояния по тикам, поэтому UI не подвисает. 3. Вход — функция горячей клавиши, а не пункт меню. 4. Отрисовка перерисовывает только помеченные элементы (массив флагов). В нашей прошивке всё это ложится на уже найденные точки: хук `0x080207E6` (отрисовка) и `0x08020816` (клавиши) в `ui_tick_normal @0x080207DC`, диспетчеризация по `g_screen @0x200008B3`. Обязательно **вызывая оригинальный обработчик** — см. `docs/firmware-parts.md`.