Files
viktorиClaude Opus 4.8 7e64e7a902 TX-фикс: DMR VCXO-трим 0x40->0x80 (= проверенный аналоговый) через 0x68, сохранён в NV
Гипотеза: кварц общий (аналог TX на частоте), а DMR трим (0xB4)=0x40 vs аналог 0x80 давал сдвиг.
Записал DMR VCCN band1&2=0x80 + CmdWriteAll. Обратимо (baseline 0x3f/0x40). tools/module_calfix.py.
Осталось проверить DMR TX в обычном режиме.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NikMGoqQWWk9wy2ww2vJAr
2026-07-24 23:12:04 +09:00

48 строки
2.3 KiB
Python

#!/usr/bin/env python3
"""RT-4D DMR-модуль: чтение/запись частотного трима VCCN через 0x68 (Linux, ttyACM0).
Рация в режиме «Обновление DMR чипа». 0x68: 68 cmd 01 01 00 00 lenHi lenLo <payload> 10 (CRC не проверяется).
"""
import serial, time, sys, argparse
def frame(cmd, payload=b""):
return bytes([0x68,cmd,1,1,0,0,(len(payload)>>8)&0xFF,len(payload)&0xFF])+payload+bytes([0x10])
def xfer(sp, fr, wait=0.4):
sp.reset_input_buffer(); sp.write(fr); time.sleep(0.03)
b=b""; t=time.time()
while time.time()-t<wait:
n=sp.in_waiting
if n: b+=sp.read(n); t=time.time()
else: time.sleep(0.005)
return b
def parse(rx):
if len(rx)<9 or rx[0]!=0x68: return None
ln=(rx[6]<<8)|rx[7]; return dict(cmd=rx[1],st=rx[3],pl=rx[8:8+ln])
def main():
ap=argparse.ArgumentParser()
ap.add_argument("--port",default="/dev/ttyACM0")
ap.add_argument("--write",action="store_true")
ap.add_argument("--val",type=lambda x:int(x,0),default=0x80)
a=ap.parse_args()
sp=serial.Serial(a.port,115200,timeout=0)
p=parse(xfer(sp,frame(0x84))) # ping
print("ping:", "OK" if p and p['cmd']==0x84 else "НЕТ ОТВЕТА (рация в режиме прошивки?)")
if not p: return
xfer(sp,frame(0xB0,bytes([1,1]))) # OpenCal
def rd(band):
r=parse(xfer(sp,frame(0xB4,bytes([0,band]))))
return r['pl'][-1] if r and r['pl'] else None
b1,b2=rd(1),rd(2)
print(f"DMR VCCN сейчас: band1=0x{b1:02x} band2=0x{b2:02x}" if b1 is not None else "чтение не удалось")
a2=parse(xfer(sp,frame(0xB2,bytes([0,2])))) # analog band2
print(f"ANA VCCN band2=0x{a2['pl'][-1]:02x}" if a2 and a2['pl'] else "ANA read fail")
if a.write:
print(f"--> пишу DMR VCCN band1&2 = 0x{a.val:02x}")
xfer(sp,frame(0xB4,bytes([1,1,a.val]))) # write band1
xfer(sp,frame(0xB4,bytes([1,2,a.val]))) # write band2
w=parse(xfer(sp,frame(0xBD,bytes([1])))) # WriteAll
print(" WriteAll:", "OK" if w and w['st']==0 else f"st={w['st'] if w else '?'}")
nb1,nb2=rd(1),rd(2)
print(f" прочитал обратно: band1=0x{nb1:02x} band2=0x{nb2:02x}")
xfer(sp,frame(0xB0,bytes([1,0]))) # CloseCal
sp.close()
if __name__=="__main__": main()