Реверс прошивки модуля FM100B: архитектура + что такое вокодер

docs/fm100b-firmware-re.md: образ = ARM(старт)+Thumb-2/FPU, 1.5МБ, без символов,
база RAM ~0x0360xxxx. Карта регионов. КЛЮЧЕВОЕ: «Vocoder» в прошивке = WebRTC
audio (шумодав NSX + AGC, открытый код), а НЕ AMBE. Сам AMBE — вне ARM-образа
(DSP/ROM A6), в прошивке только интерфейс ATVoiceEnc/Dec + RecvAmbedata. Найдены
open-source либы: EasyFlash (NV/калибровка), WebRTC (аудио). Честная оценка: свой
вокодер для эфирного DMR невозможен (нет AMBE-совместимости); реально моддить —
WebRTC-параметры, кодек-гейны, NV-калибровку, логику DMR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NikMGoqQWWk9wy2ww2vJAr
Этот коммит содержится в:
2026-07-24 04:28:45 +09:00
co-authored by Claude Opus 4.8
родитель f2617a2e79
Коммит 7c6c2dfea7
2 изменённых файлов: 59 добавлений и 5 удалений
+8 -5
Просмотреть файл
@@ -24,7 +24,10 @@ CMDS = {
"CmdEnd": "34 52 05 ee 79",
}
def hx(name): return bytes.fromhex(CMDS[name].replace(" ", ""))
def hx(name):
if name.startswith("hex:"):
return bytes.fromhex(name[4:].replace(" ", ""))
return bytes.fromhex(CMDS[name].replace(" ", ""))
# powershell: open port, run a sequence of (write, wait) steps, capture each response
PS = r'''
@@ -47,7 +50,7 @@ foreach ($s in $steps) {{
if ($buf.Count -gt 0 -and ($sw.ElapsedMilliseconds-$last) -gt {idle}) {{ break }}
}}
$hex = ($buf | ForEach-Object {{ "{{0:x2}}" -f $_ }}) -join ""
Write-Output ("RSP:"+$name+":"+$hex)
Write-Output ("RSP|"+$name+"|"+$hex)
}}
$p.Close()
Write-Output "DONE"
@@ -72,8 +75,8 @@ def run(port, seq, dwell=120, tmo=700, idle=200):
res=[]
for line in out.split("\n"):
if line.startswith("ERR:"): sys.exit(line)
if line.startswith("RSP:"):
_,name,hexs=line.split(":",2)
if line.startswith("RSP|"):
_,name,hexs=line.split("|",2)
res.append((name, bytes.fromhex(hexs) if hexs else b""))
return res
@@ -107,7 +110,7 @@ def main():
print("Нет ответов от рации (powershell не вернул RSP). Порт/режим?")
return
for name,rx in res:
tag=f" {name:12s} TX={CMDS[name]}"
tag=f" {name:14s} TX={CMDS.get(name, name[4:] if name.startswith('hex:') else name)}"
if not rx:
print(tag+" RX=(нет ответа)")
else: