Files
viktor 6d49ba3cba 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

39 строки
2.2 KiB
Python

#!/usr/bin/env python3
"""spi_wr.py REGION SRCADDR SIZE — пишет SIZE байт из radio-spi-dump.bin[SRCADDR]
в SPI рации регионом REGION (блоки 0..). Рация в обычном режиме. CPS через powershell."""
import subprocess, sys, os
WIN_TMP_WSL="/mnt/c/Users/vikto/AppData/Local/Temp"; WIN_TMP_WIN=r"C:\Users\vikto\AppData\Local\Temp"
region=int(sys.argv[1],0); srcaddr=int(sys.argv[2],0); size=int(sys.argv[3],0)
ref=open("radio-spi-dump.bin","rb").read()
data=ref[srcaddr:srcaddr+size]
open(os.path.join(WIN_TMP_WSL,"rt4d_wr.bin"),"wb").write(data)
dw=os.path.join(WIN_TMP_WIN,"rt4d_wr.bin").replace("\\","\\\\")
out=subprocess.run(["powershell.exe","-NoProfile","-Command","[System.IO.Ports.SerialPort]::GetPortNames() -join ','"],capture_output=True,text=True).stdout
port=[x for x in out.strip().replace("\r","").split(",") if x][0]
PS=f'''
$ErrorActionPreference='Stop'
$data=[System.IO.File]::ReadAllBytes("{dw}")
$p=New-Object System.IO.Ports.SerialPort "{port}",115200,"None",8,"one"
$p.ReadTimeout=1500;$p.WriteTimeout=3000
$p.Open()
function ck([byte[]]$a,$n){{$s=0;for($i=0;$i -lt $n;$i++){{$s=($s+$a[$i]) -band 0xFF}};return [byte]$s}}
$p.DiscardInBuffer();$nf=[byte[]](0x34,0x00,0x00,0x10,0x44);$p.Write($nf,0,5)
$ok=$false;$sw=[Diagnostics.Stopwatch]::StartNew()
while($sw.ElapsedMilliseconds -lt 3000){{try{{if($p.ReadByte() -eq 6){{$ok=$true;break}}}}catch{{}}}}
if(-not $ok){{Write-Output "ERR:notify";exit 1}}
Write-Output "notify ok"
for($i=0;$i -lt {size};$i+=1024){{
$cmd=New-Object byte[] 1028;$cmd[0]={region}
$blk=[int]($i/1024);$cmd[1]=(($blk -shr 8) -band 0xFF);$cmd[2]=($blk -band 0xFF)
[Array]::Copy($data,$i,$cmd,3,1024);$cmd[1027]=ck $cmd 1027
$p.DiscardInBuffer();$p.Write($cmd,0,1028)
$ok=$false;$sw2=[Diagnostics.Stopwatch]::StartNew()
while($sw2.ElapsedMilliseconds -lt 3000){{try{{if($p.ReadByte() -eq 6){{$ok=$true;break}}}}catch{{}}}}
if(-not $ok){{Write-Output ("ERR@"+$blk);exit 1}}
Write-Output ("blk "+$blk)
}}
$cl=[byte[]](0x34,0x52,0x05,0xEE,0x79);$p.Write($cl,0,5);$p.Close();Write-Output "OK"
'''
r=subprocess.run(["powershell.exe","-NoProfile","-Command",PS],capture_output=True,text=True,encoding="utf-8",errors="replace")
print(r.stdout.strip()[-400:])