Project

General

Profile

New Model #9241 » parse_dat.py

Fred DeKeyser, 01/12/2025 10:28 PM

 
def print_block(array, width, size) :
i = 0
while i < size :
j = i + width
print(array[i:min(j,size)].hex(' '))
i = j

import struct

def dump(file, name, width, num, extra=0) :
pos = file.tell()
buf = bytearray((width*num)+extra)
len = file.readinto(buf)
print("> %s: %04x at %08x" %(name, len, pos))
if 0 == len : return 0
print_block(buf, width, len)
return struct.unpack_from('<H', buf) # 2 byte unsigned short little-endian

def skip(file, name, width, num, extra=0) :
pos = file.tell()
len = (width*num)+extra
file.seek(len, 1)
print("> %s: %04x at %08x" %(name, len, pos))
return 0

def extract(file, num) :
print("> Memory channel data:")
file.seek(0x25a3)
buf = bytearray(119*num)
len = file.readinto(buf)
for i in range(0, len, 119) :
tuple = struct.unpack_from("<3H9s9s8s4H6x3H4xH10x4s4s9H6xH2xH4x5sH2x", buf, i)
print(tuple)

import sys

if len(sys.argv) <= 1 : sys.exit("File name not specified.")
with open(sys.argv[1]+".dat", 'rb', buffering=0) as F :
dump(F, "Frequency Range", 2, 1) # 0x0000
skip(F, "DTMF Array", 18, 20) # 0x0002
skip(F, "DTMF", 27, 1) # 0x016a
skip(F, "2Tone", 42, 1) # 0x0185
skip(F, "2Tone Array", 17, 32) # 0x01af
skip(F, "5Tone", 28, 1) # 0x03cf
skip(F, "5Tone Info IDs", 22, 8) # 0x03eb
skip(F, "5Tone Encode IDs", 53, 102) # 0x049b
skip(F, "Zeros (constant)", 29, 1) # 0x19b9
skip(F, "Settings", 76, 1) # 0x19d6
dump(F, "Display", 16, 1) # 0x1a22 + 16 characters (2 lines of 8)
skip(F, "Scan Info", 14, 1) # 0x1a32
skip(F, "Emergency Info", 12, 1) # 0x1a40
count = dump(F, "Channel Count", 2, 1) # at file offset 0x1a4c
skip(F, "Zeros (constant)", 32, 37, 30) # 0x1a4e
skip(F, "Comm Notes", 13, 128, 1) # 0x1f0c
dump(F, "Radio Model", 16, 1) # 0x258d
dump(F, "CPS Version", 4, 1) # 0x259d
dump(F, "CPS Zero, Radio Four", 2, 1) # 0x25a1
skip(F, "Channels", 119, count[0]) # starts at file offset 0x25a3
# 4th byte from the ends seems to be with scan info...
dump(F, "Pad (variable)", 6, 1)
dump(F, "Unparsed", 32, 16)
print("End parsing at %08x" %(F.tell()))
extract(F, count[0])

# Special channel indices: PL1=0x1F5 PH1=0x1F6 PL2=0x1F7 PH2=0x1F8 VFO1=0x1F9 VFO2=0x1FA
(8-8/8)