From 1dedc4150b4f10ed45abf93d4cb3280a00e6fbeb Mon Sep 17 00:00:00 2001 From: viktor Date: Fri, 24 Jul 2026 05:40:37 +0900 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=A0=D0=9E=D0=A0=D0=AB=D0=92:=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D1=87=D0=B8=D0=BA=20HKLFBOOT=20?= =?UTF-8?q?=D0=B4=D0=BE=D1=81=D1=82=D0=B8=D0=B6=D0=B8=D0=BC=20+=20=D0=92?= =?UTF-8?q?=D0=A7-=D1=87=D0=B8=D0=BF=20=3D=20BK4819?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Слушая COM при включении в режим прошивки, поймал boot модуля: баннер HKLFBOOT...... VERSION:01020032 RF_IC:BK_4819. ВЧ-трансивер = Beken BK4819 (как в UV-K5, полностью реверснут) -> частотная калибровка = регистры BK4819, можно чинить TX по мануалу. Загрузчик HKLFBOOT достижим через мост (мост прозрачен, CH34x держит связь через перезагрузку), ждёт хендшейк в окне '......'; стандартный Beken 01 E0 FC не подходит. Обновлены docs/fm100b-firmware-re.md, память. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NikMGoqQWWk9wy2ww2vJAr --- docs/fm100b-firmware-re.md | 17 ++++++++++ tools/bk_bootloader_catch.py | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tools/bk_bootloader_catch.py diff --git a/docs/fm100b-firmware-re.md b/docs/fm100b-firmware-re.md index 6ee9655..455f50d 100644 --- a/docs/fm100b-firmware-re.md +++ b/docs/fm100b-firmware-re.md @@ -140,3 +140,20 @@ download-режим) при владельце, с риском. Пока вла 2. **WebRTC-параметры:** найти конфиг NSX/AGC (режим/пороги) в коде, изменить, перешить модуль (режим «Обновление DMR чипа»), проверить звук/приём. Это и есть «поменять и посмотреть заведётся ли». 3. **EasyFlash NV:** распарсить NV-регион (cal) во flash-дампе — прямой доступ к калибровке без live-протокола. + +## ⭐⭐ ПРОРЫВ (24.07): загрузчик HKLFBOOT + ВЧ-чип BK4819 +Слушая COM во время включения рации в режим «Обновление DMR чипа», поймал загрузку модуля +(мост ПРОЗРАЧНО передаёт boot; CH34x-шнурок держит связь через перезагрузку рации): +``` +\r\nHKLFBOOT......\r\n VERSION:01020032\r\n RF_IC:BK_4819\r\n +68 06 02 76 85 83 00 00 10 (далее приложение шлёт 0x68) +``` +- **RF_IC = BK4819** — ВЧ-трансивер модуля = **Beken BK4819** (тот же, что в Quansheng UV-K5, + ПОЛНОСТЬЮ реверснут сообществом). Частотная калибровка/девиация/AFC RT-4D = **регистры BK4819**. + SPCali_* (0xB4 VCCN=freq-трим, FreqOpt, DigMod=девиация) отображаются в регистры BK4819. + → чинить TX можно по документации BK4819 (UV-K5), возможно без полного дампа. +- **Загрузчик = «HKLFBOOT»** (кастом, не гуглится). ДОСТИЖИМ через мост, ждёт хендшейк во время + «......», затем грузит app. Стандартный Beken `01 E0 FC` НЕ подходит. Инструменты: + `tools/bk_bootloader_catch.py` (ловит баннер/линк), `tools/bk_deinterleave.py` (снять CRC с дампа). +- Дамп флеша модуля разблокируется, как найдём HKLF-хендшейк (реверс прошивки AT32 «Update DMR Chip», + либо аккуратный перебор в boot-окне). Тогда получим RF Firmware (AMBE) + NET info (NV). diff --git a/tools/bk_bootloader_catch.py b/tools/bk_bootloader_catch.py new file mode 100644 index 0000000..8a84596 --- /dev/null +++ b/tools/bk_bootloader_catch.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +"""Поймать Beken-загрузчик модуля во время включения (через мост RT-4D, WSL/powershell). + +Формат флеша модуля = стандартный Beken (32+2 CRC), значит у него Beken UART-загрузчик, +который слушает link-check КОРОТКОЕ окно после сброса. Этот тул одним процессом powershell +в тайтовом цикле спамит link-check `01 E0 FC 01 00` и ловит ответ `04 0E 05 ...`. + +Использование: запусти тул, и в течение его работы ВЫКЛЮЧИ и включи рацию в режим +«Обновление DMR чипа» (питание + MENU). Если поймаем ответ — загрузчик достижим через мост. + +ТОЛЬКО ЧТЕНИЕ/handshake — ни erase, ни write не шлём. +""" +import argparse, subprocess, sys + +PS = r''' +$port="{port}"; $sec={sec} +$p = New-Object System.IO.Ports.SerialPort $port,115200,"None",8,"one" +$p.ReadTimeout=20; $p.WriteTimeout=50 +try {{ $p.Open() }} catch {{ Write-Output "ERR:$($_.Exception.Message)"; exit }} +$lc=[byte[]]@(1,224,252,1,0) # 01 E0 FC 01 00 +$sw=[Diagnostics.Stopwatch]::StartNew() +$hit=$false +while($sw.Elapsed.TotalSeconds -lt $sec){{ + try {{ $p.Write($lc,0,$lc.Length) }} catch {{}} + Start-Sleep -Milliseconds 8 + $n=$p.BytesToRead + if($n -gt 0){{ + $b=New-Object byte[] $n; $p.Read($b,0,$n)|Out-Null + $hex=($b|ForEach-Object{{"{{0:x2}}"-f $_}}) -join "" + if($hex -match "e0fc"){{ Write-Output ("HIT:"+$hex); $hit=$true; break }} + else {{ Write-Output ("RX:"+$hex) }} + }} +}} +$p.Close() +if(-not $hit){{ Write-Output "NOHIT" }} +''' + +def main(): + ap=argparse.ArgumentParser() + ap.add_argument("--port", default="COM4") + ap.add_argument("--sec", type=int, default=25) + a=ap.parse_args() + print(f"[спам link-check на {a.port} @115200, {a.sec}с]") + print(">>> СЕЙЧАС выключи рацию и включи в режим «Обновление DMR чипа» (питание+MENU) <<<\n") + r=subprocess.run(["powershell.exe","-NoProfile","-Command",PS.format(port=a.port,sec=a.sec)], + capture_output=True, text=True) + for line in r.stdout.replace("\r","").split("\n"): + line=line.strip() + if line.startswith("HIT:"): + print(f"✅ ЗАГРУЗЧИК ОТВЕТИЛ: {line[4:]}") + print(" -> Beken-загрузчик достижим через мост. Можно читать флеш.") + elif line.startswith("RX:") and line[3:]: + print(f" (эхо/данные: {line[3:][:60]})") + elif line=="NOHIT": + print("❌ Ответа загрузчика не поймано. Либо мост не пробрасывает загрузчик,") + print(" либо окно/бод другие. Попробуй ещё раз или обсудим физ.доступ.") + elif line.startswith("ERR:"): + print(line) + +if __name__=="__main__": + main()