import struct, 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()

# 0x126000 decode as call-log. Fields observed:
# b0=00, b1=type(1=priv/grp,2=?), b2=01, b3=00, b4-5=?, b6-9=dmr_id LE, b10-13=counter LE,
# b14-19 = YY MM DD HH MM SS, rest 0
print("### 0x126000 decoded call-log entries ###")
for i in range(16):
    o=0x126000+i*32
    r=data[o:o+32]
    if r[14]==0 and all(b==0 for b in r[:14]): break
    b1=r[1]; b4=struct.unpack('<H',r[4:6])[0]
    dmr=struct.unpack('<I',r[6:10])[0]
    cnt=struct.unpack('<I',r[10:14])[0]
    date=f"20{r[14]:02d}-{r[15]:02d}-{r[16]:02d} {r[17]:02d}:{r[18]:02d}:{r[19]:02d}"
    print(f" #{i:2d} type={b1} b4={b4:04x} dmr_id={dmr}(0x{dmr:x}) seq={cnt} {date}")
# region schedules is at 0xC6000. call_log at 0x88000 region. 0x126000 is unrelated location.
# Occupancy said call_log used @0x092000 (that was actually contacts-looking / All Call).
# Let's see total valid + gap pattern
print("\ntotal 32-byte records with a nonzero timestamp year 0x19:")
n=sum(1 for i in range(20480//32) if data[0x126000+i*32+14]==0x19)
print(n)

# Confirm the 0x100000 bitmap: render 1bpp. It has 5-row-tall column data (values <=0x1f then 0x3c,0x38 etc)
print("\n### 0x100000 bitmap render (bytes as vertical 8px columns, LSB=top) ###")
seg=data[0x100000:0x100000+0x300]
# print 8 rows
for row in range(8):
    line=''
    for col in range(0x190,0x2f8):
        b=data[0x100000+col]
        line+='#' if (b>>row)&1 else ' '
    print(line.rstrip())

# 0x03E000 twin: what is at 0x01E000 exactly and how does it relate to zones?
print("\n### 0x01E000 (inside zones region) full ###")
def hd(off,n):
    out=[]
    for i in range(0,n,16):
        c=data[off+i:off+i+16]
        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'{off+i:08x}  {h:<47}  {a}')
    return '\n'.join(out)
print(hd(0x01e000,48))
# Is 0x01E000 the tail of the last zone slot? zones start 0x01C000, 512B each. 0x01E000 = slot 16.
print(f"0x01E000 is zone slot #{(0x01E000-0x01C000)//512}")
# The DTCN A/B marker in beta is at page+0xFF8. 0x01dffc had ff ff ff ff before DMRhub.
# So 0x01E000 likely a settings/identity page, twinned at 0x03E000.
