import struct, collections, sys, io sys.stdout=io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') DUMP=r"C:/Users/vikto/Documents/Claude/rt-4d/radio-spi-dump.bin" data=open(DUMP,'rb').read() def hd(off,n=128,base=None): base=off if base is None else base out=[] for i in range(0,n,16): c=data[off+i:off+i+16] if not c:break h=' '.join(f'{b:02x}' for b in c) a=''.join(chr(b) if 32<=b<127 else '.' for b in c) out.append(f'{base+i:08x} {h:<47} {a}') return '\n'.join(out) # 0x14C000: GBK char table. Decode as GBK 2-byte print("### 0x14C000 GBK char list (first 40 chars) ###") seg=data[0x14c000:0x14c000+80] chars=[] i=0 while i < len(seg)-1: b=seg[i] if b>=0x81: try: ch=bytes([seg[i],seg[i+1]]).decode('gbk') chars.append(ch); i+=2; continue except: pass i+=1 print(''.join(chars)) # Size and how it ends end=0x14c000+0xB000 print("tail of 0x14C000 region:") print(hd(end-64,64)) # Correlate: 0x14C000 is a GBK char table (34KB?) and 0x164000 pinyin (200KB). # The pinyin region: are entries fixed 6 bytes each -> index maps to char in char table? print("\n### relationship: char count vs pinyin count ###") # count 2-byte gbk chars in 0x14C000..0x157000 (44KB used, then zeros) charseg=data[0x14c000:0x157000] nchars=0 i=0 while i=0x81 and charseg[i+1]!=0x00: nchars+=1; i+=2 else: i+=1 print(f"approx gbk chars in 0x14C000-0x157000 (44KB): {nchars}") # pinyin at 0x164000, 6 bytes each, over 200KB print(f"pinyin entries if 6-byte: {0x32000//6}") print(f"pinyin entries if 8-byte: {0x32000//8}") # Check pinyin stride precisely: look for the pattern of fixed-width fields print("\n### pinyin stride check: line up 'kao','shang','xia' ###") # they appeared as 6-char fields: 'kao ','shang ','xia ' for w in range(4,10): # test if every field is exactly w and space padded ok=True for k in range(20): f=data[0x164000+k*w:0x164000+k*w+w] # must be ascii letters+spaces if not all(32<=b<127 for b in f): ok=False;break if ok: fields=[data[0x164000+k*w:0x164000+k*w+w] for k in range(12)] print(f"w={w}: {[f.decode() for f in fields]}") # 0x100000 region: mostly zeros with some ascii. dump non-zero area print("\n### 0x100000 non-zero content ###") for i in range(0,0x1000,16): c=data[0x100000+i:0x100000+i+16] if any(b!=0 for b in c): h=' '.join(f'{b:02x}' for b in c) a=''.join(chr(b) if 32<=b<127 else '.' for b in c) print(f'{0x100000+i:08x} {h:<47} {a}') # 0x03E000 DMRhub: bytes 0-3 = 00 00 00 00 then name. This resembles radio identity/owner? # main_settings radio_name at cfg+76. Check cfg region for DMRhub print("\n### search whole dump for 'DMRhub' ###") o=0 while True: o=data.find(b'DMRhub',o) if o<0:break print(f" @{o:08x}: {hd(o-8,32,o-8)}") o+=1 # 0x0D0000 keys: is this the 'groups'/grouplist backup? name 'Key N', b0=index, tail has index at +20 # Compare with grouplist format (b1==0x01 enabled, name @0x02). Here b0=idx,b1=00,name@2. # Actually looks like encryption keys OR group lists. Check groups region 0x07C000 print("\n### groups region 0x07C000 ###") print(hd(0x07c000,96)) # and encrypt region in .4rdmf is separate. Let's see full first key record 48 bytes across print("\n### 0x0D0000 full stride verify: is it 0x30? show rec 100 ###") print(hd(0x0d0000+100*0x30,48)) print("last populated:") print(hd(0x0d0000+509*0x30,48))