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).
Этот коммит содержится в:
@@ -0,0 +1,38 @@
|
||||
#!/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:])
|
||||
Ссылка в новой задаче
Block a user