# UA1ZBE Custom Firmware — Полная документация

## 1. Обзор архитектуры

Прошивка заменяет стандартное меню и создаёт три режима: VFO, POCSAG, Spectrum + FM.

### Точка входа: `main.c`

```
Main()
  ├── SYSTICK_Init(), BOARD_Init()
  ├── BK4819_Init()
  ├── SETTINGS_InitEEPROM()
  ├── RADIO_ConfigureChannel()
  ├── BOOT_SplashShow()        ← 2 сек заставка
  ├── RSSI_Init()
  ├── MODE_Init()              ← VFO режим по умолчанию
  └── while(1):
        ├── APP_Update()
        ├── if (gNextTimeslice):
        │     ├── RSSI_Update()
        │     └── MODE_TimeSlice10ms()
        └── if (gNextTimeslice_500ms):
              └── MODE_TimeSlice500ms()
```

### Диспетчер режимов: `app/mode.c`

```
MODE_TimeSlice10ms()
  ├── MODE_VFO:
  │     └── APP_TimeSlice10ms()  ← оригинальный VFO цикл
  │     └── RSSI_Draw()          ← overlay индикатор
  ├── MODE_POCSAG:
  │     └── POCSAG_FeedSample() × 80  ← аудио сэмплинг
  │     └── POCSAG_Process()
  │     └── pocsag_draw()
  ├── MODE_SPECTRUM:
  │     └── MODE_Switch(MODE_VFO)  ← после возврата из spectrum
  └── MODE_FM:
        └── FM_Play()
```

---

## 2. Все ошибки при создании и их исправления

### Ошибка 1: `static_assert` не работает в C99

```
error: expected declaration specifiers or '...' before '(' token
   static_assert(ARRAY_SIZE(ProcessKeysFunctions) == DISPLAY_N_ELEM);
```

**Причина:** `static_assert` — C11 feature. В `-std=c99` недоступен.

**Исправление:** Заменил `-std=c99` на `-std=gnu11` в Makefile.

---

### Ошибка 2: `[[fallthrough]]` не поддерживается GCC 9

```
error: expected expression before '[' token
    [[fallthrough]];
```

**Причина:** Атрибут `[[fallthrough]]` — синтаксис C23. GCC 9.2.1 не понимает.

**Исправление:**
```bash
sed -i 's/\[\[fallthrough\]\]/__attribute__((fallthrough))/g' \
  radio.c audio.c app/menu.c app/dtmf.c app/chFrScanner.c
```

---

### Ошибка 3: `SYSTICK_GetTickCounter()` не существует

**Причина:** В egzumer нет этой функции.

**Исправление:** В `pocsag.c` использован собственный статический счётчик `s_tick_counter`, инкрементируемый при каждом вызове `POCSAG_FeedSample()`.

---

### Ошибка 4: Сравнение `uint8_t >= 576` — всегда false

```
error: comparison is always false due to limited range of data type
  if (s_preamble_alt_count >= POCSAG_PREAMBLE_MIN_BITS)
```

**Причина:** `s_preamble_alt_count` был `uint8_t` (макс 255), а `POCSAG_PREAMBLE_MIN_BITS` = 576.

**Исправление:**
```c
static uint16_t s_preamble_alt_count;  // было uint8_t
```

---

### Ошибка 5: `dBmCorrTable` undeclared

```
error: 'dBmCorrTable' undeclared (first use in this function)
```

**Причина:** Таблица в `ui/main.c`, но нет extern в заголовке.

**Исправление:** Добавил в `display_rssi.c`:
```c
extern const int8_t dBmCorrTable[7];
```

---

### Ошибка 6: `display_rssi.h` не найден

```
fatal error: display_rssi.h: No such file or directory
```

**Исправление:** Заменил `#include "display_rssi.h"` на `#include "app/display_rssi.h"` везде.

---

### Ошибка 7: `sizeof` к неполному типу

```
error: invalid application of 'sizeof' to incomplete type 'char[]'
```

**Исправление:** Добавил `#include "app/dtmf.h"` в `main.c` — там полное объявление `extern char gDTMF_String[15]`.

---

### Ошибка 8: 40+ undefined reference

```
undefined reference to `gScreenToDisplay'
undefined reference to `GUI_SelectNextDisplay'
undefined reference to `GENERIC_Key_F', `ACTION_Scan'...
```

**Причина:** Исключил модули, но `app/app.c` и `app/main.c` их используют.

**Исправление:** Вернул в Makefile: `ui/ui.o`, `ui/inputbox.o`, `ui/menu.o`, `ui/welcome.o`, `ui/scanner.o`, `app/menu.o`, `app/generic.o`, `app/action.o`, `app/dtmf.o`

---

### Ошибка 9: `_sbrk` undefined

```
undefined reference to `_sbrk'
```

**Исправление:** Создал `syscalls.c`:
```c
caddr_t _sbrk(int incr) {
    (void)incr;
    return (caddr_t)0;
}
```

---

### Ошибка 10: `UI_DisplayReleaseKeys` / `UI_DisplayScanner`

**Исправление:** Добавил `ui/welcome.o` и `ui/scanner.o`.

---

## 3. Известные проблемы для доработки

### 3.1. POCSAG — недостаточно сэмплов

**Проблема:** `POCSAG_FeedSample()` вызывается ~1 раз/10мс. Для 1200 бод нужно ~1 раз/125мкс.

**Решение:**
```c
// В mode.c, case MODE_POCSAG:
for (int i = 0; i < 80; i++) {
    uint16_t audio = BK4819_GetVoiceAmplitudeOut();
    POCSAG_FeedSample(audio);
    SYSTEM_DelayUs(125);
}
```

### 3.2. Нет отображения текста POCSAG сообщений

**Решение:** В `pocsag_draw()` добавить:
```c
static pocsag_msg_t last_msg;
if (POCSAG_GetMessage(&last_msg)) {
    UI_PrintStringSmallNormal(last_msg.text, 0, 120, 28);
}
```

### 3.3. Дублирование APP_TimeSlice

`MODE_TimeSlice10ms()` вызывает `APP_TimeSlice10ms()`, что дублирует обработку.

**Решение:** Разделить — для VFO вызывать `APP_TimeSlice10ms()`, для POCSAG — только `CheckRadioInterrupts()`.

### 3.4. Flash на пределе (94.3%)

Осталось ~3.5 КБ. Для экономии можно отключить:
```makefile
ENABLE_FMRADIO   = 0   # -2 КБ
ENABLE_SPECTRUM  = 0   # -5 КБ
```

---

## 4. Инструкция по сборке

```bash
# Тулчейн
sudo apt-get install gcc-arm-none-eabi

# Сборка
cd uv-k5-firmware-custom
make clean && make

# Результат
arm-none-eabi-size firmware
#   text    data     bss     dec     hex filename
#  57708     204    3364   61276    ef5c firmware
```

---

## 5. Инструкция по прошивке

### Вариант 1: SWD (J-Link)

```bash
# Установка OpenOCD
sudo apt-get install openocd

# Подключение:
# J-Link Pin 1 (VTref) — 3.3V
# J-Link Pin 2 (GND)   — GND
# J-Link Pin 7 (SWDIO) — SWDIO на плате
# J-Link Pin 9 (SWCLK) — SWCLK на плате

make flash
# Или вручную:
openocd -f interface/jlink.cfg -f dp32g030.cfg \
  -c "write_image firmware.bin 0; shutdown;"
```

### Вариант 2: UART

```bash
git clone https://github.com/piotr02/k5prog.git
cd k5prog && make && sudo cp k5prog /usr/local/bin/

# Включить рацию с зажатой SK2
k5prog -f firmware.bin -p /dev/ttyUSB0 -w
```

### Вариант 3: USB

```bash
# Выключить → зажать PTT+SK2 → включить
k5prog -f firmware.bin -w
```

---

## 6. Структура файлов

| Файл | Назначение |
|------|-----------|
| `Makefile` | Конфигурация сборки, флаги |
| `main.c` | Точка входа, инициализация, главный цикл |
| `syscalls.c` | Заглушка _sbrk для bare-metal |
| `app/boot_splash.c` | Заставка UA1ZBE / 2 сек |
| `app/display_rssi.c` | RSSI индикатор в dBm |
| `app/mode.c` | Диспетчер режимов |
| `app/pocsag/pocsag.c` | POCSAG декодер |
| `app/pocsag/bch31.c` | BCH(31,21) коррекция |

---

## 7. Отладочные команды

```bash
# Размер секций
arm-none-eabi-size -A firmware | sort -n -k2 | tail -20

# Символы
arm-none-eabi-nm --size-sort firmware | tail -30

# Дизассемблер
arm-none-eabi-objdump -d firmware | grep -A20 "<POCSAG_FeedSample>:"

# Проверка переполнения
SIZE=$(wc -c < firmware.bin)
[ $SIZE -gt 61440 ] && echo "OVERFLOW!" || echo "OK: $SIZE / 61440"
```
