#!/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()
