--- /dev/null
+#!/usr/bin/env python
+
+"""
+Unpacker for HLD files
+
+Written for Python3+
+"""
+
+import struct
+import pdb
+import math
+import io
+
+from .utils import split_by_n, str_32bit_chunks
+
+#### ------ Size definitions for the HLD files ------ ####
+
+# we have 32bit words (i.e. 4 bytes per word)
+WORDSIZE = 4
+# The smallest unit to read is a block of 2 words (64bit)
+BLOCKSIZE = WORDSIZE * 2
+
+#### ------ Class definitions representing (sub) events ------ ####
+
+class Event(object):
+
+ # the event header consists of 8 words
+ HEADERSIZE = WORDSIZE * 8
+
+ def __init__(self, header_bytes, payload_bytes):
+ self.header_bytes = header_bytes
+ self.payload_bytes = payload_bytes
+ struct_fmt = '<{:d}I'.format(Event.HEADERSIZE//WORDSIZE)
+ self.header_words = struct.unpack(struct_fmt, header_bytes)
+ self._set_properties(*self.header_words)
+ self.subevents = list(read_subevents(io.BytesIO(self.payload_bytes)))
+
+ def _set_properties(self, size, decoding, id, seqnr, date, time, runnr, expid):
+ self.size = size
+ self.decoding = decoding
+ self.id = id
+ self.seqnr = seqnr
+ self.date = date
+ self.time = time
+ self.runnr = runnr
+ self.expid = expid
+
+ def __str__(self):
+ fmt = "size: 0x{:08x} decoding: 0x{:08x} id: 0x{:08x} seqnr: 0x{:08x}\n"
+ out = fmt.format(self.size, self.decoding, self.id, self.seqnr)
+ fmt = "date: 0x{:08x} time: 0x{:08x} runnr: 0x{:08x} expid: 0x{:08x}\n"
+ out += fmt.format(self.date, self.time, self.runnr, self.expid)
+ #out += "\n"
+ #out += str_32bit_chunks(self.payload_bytes)
+ #out += "\n"
+ for subevent in self.subevents:
+ out += str(subevent)
+ return out
+
+class SubEvent(object):
+
+ # the event header consists of 8 words
+ HEADERSIZE = WORDSIZE * 4
+
+ def __init__(self, header_bytes, payload_bytes):
+ self.header_bytes = header_bytes
+ self.payload_bytes = payload_bytes
+ struct_fmt = '>{:d}I'.format(SubEvent.HEADERSIZE//WORDSIZE)
+ self.header_words = struct.unpack(struct_fmt, header_bytes)
+ self._set_properties(*self.header_words)
+
+ def _set_properties(self, size, decoding, id, trignr):
+ self.size = size
+ self.decoding = decoding
+ self.id = id
+ self.trignr = trignr
+
+ def __str__(self):
+ fmt = "size: 0x{:08x} decoding: 0x{:08x} id: 0x{:08x} trignr: 0x{:08x}\n"
+ out = fmt.format(self.size, self.decoding, self.id, self.trignr)
+ out += "\n"
+ out += str_32bit_chunks(self.payload_bytes)
+ return out
+
+#### ------ Generator Functions to read the HLD into the (sub)event classes ------ ####
+
+def read(hld_stream):
+ while True:
+ header_bytes = hld_stream.read(Event.HEADERSIZE)
+ if len(header_bytes) < Event.HEADERSIZE: break
+ # The size of the event in bytes is given in the first data word of the event.
+ # The size also includes the 4 bytes of its own data word:
+ size = struct.unpack('<I', header_bytes[:WORDSIZE])[0]
+ # We read already the full header, so we need to subtract
+ actual_num_bytes = size - Event.HEADERSIZE
+ # The HLD file always writes blocks of length BLOCKSIZE and pads with 0x00 bytes at the end of blocks
+ remaining_num_bytes = int(math.ceil(actual_num_bytes/BLOCKSIZE)*BLOCKSIZE)
+ data_bytes = hld_stream.read(remaining_num_bytes)
+ data_bytes = data_bytes[:actual_num_bytes]
+ #pdb.set_trace()
+ yield Event(header_bytes, data_bytes)
+
+def read_subevents(subevents_stream):
+ while True:
+ header_bytes = subevents_stream.read(SubEvent.HEADERSIZE)
+ if len(header_bytes) < SubEvent.HEADERSIZE: break
+ # The size of the event in bytes is given in the first data word of the event:
+ size = struct.unpack('>I', header_bytes[:WORDSIZE])[0]
+ # We read already all bytes belonging to the header, so we need to subtract them
+ actual_num_bytes = size - SubEvent.HEADERSIZE
+ remaining_num_bytes = int(math.ceil(actual_num_bytes/BLOCKSIZE)*BLOCKSIZE)
+ data_bytes = subevents_stream.read(remaining_num_bytes)
+ data_bytes = data_bytes[:actual_num_bytes]
+ #pdb.set_trace()
+ yield SubEvent(header_bytes, data_bytes)
+
--- /dev/null
+
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
+
+setup(
+ name = 'hld_unpacker',
+ version = '0.1.0',
+ description = 'An unpacker for HLD files.',
+ author = 'Philipp Klaus',
+ author_email = 'klaus@physik.uni-frankfurt.de',
+ packages = ['hld_unpacker'],
+ scripts = ['scripts/unpack_hld',],
+ license = 'GPL',
+ long_description = '',
+ install_requires = [],
+ keywords = 'HLD unpacker HADES CBM GSI HEP',
+ classifiers = [
+ 'Development Status :: 4 - Beta',
+ 'Operating System :: OS Independent',
+ 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Topic :: Scientific/Engineering',
+ ]
+)
+
+