Source code for slap2_utils.utils.file_header
# Utility functions for the Slap2DataFile
[docs]
def load_file_header_v2(obj, rawUint32):
"""
Performs sanity checks on the file header and parses it into usable Python structures.
Parameters
----------
obj : object
An object that contains file-level metadata (e.g., constants like MAGIC_NUMBER).
rawUint32 : ``np.ndarray``
The raw header data as a uint32 array from the SLAP2 file.
Returns
-------
tuple
A tuple containing:
- ``header`` (dict): Parsed header metadata.
- ``num_cycles`` (int): Total number of cycles computed from the file size.
"""
# Data format:
# uint32_t magic_start = MAGIC_NUMBER;
# uint32_t file_version = 1;
# uint32_t fileHeaderSize_Bytes = XXXX;
#
# uint32_t fieldId = XXXX;
# uint32_t fieldVal = XXXX;
# uint32_t fieldId = XXXX;
# uint32_t fieldVal = XXXX;
#
# ...
#
# uint32_t magic_end = MAGIC_NUMBER;
file_magic_number = rawUint32[0]
assert file_magic_number == obj.MAGIC_NUMBER, 'Data format error.'
file_format_version = rawUint32[1]
assert file_format_version == 2, 'Unknown format version'
file_header_size_bytes = rawUint32[2]
file_header_entries = file_header_size_bytes // 4
header_end_magic_number = rawUint32[int(file_header_entries)-1]
assert header_end_magic_number == obj.MAGIC_NUMBER, 'Data corruption in file header.'
field_value_pairs = rawUint32[3:file_header_entries - 1]
field_value_pairs = field_value_pairs.reshape(-1, 2)
header_ = translate_field_value_pairs(field_value_pairs)
header_ = translate_channel_mask(header_)
header_ = translate_reference_timestamp(header_)
header_['file_version'] = file_format_version
header_['magic_start'] = file_magic_number
header_['magic_end'] = header_end_magic_number
header = header_
file_size_bytes = len(rawUint32) * 4
num_cycles = int((file_size_bytes - header_['firstCycleOffsetBytes']) / header_['bytesPerCycle'])
total_num_lines = num_cycles * header['linesPerCycle']
num_channels = float(header['numChannels'])
return header, num_cycles
[docs]
def translate_field_value_pairs(field_value_pairs):
"""
Maps integer field IDs to named header fields and assigns their values.
Parameters
----------
field_value_pairs : ``np.ndarray``
A (N, 2) array where each row is a field ID and its associated value.
Returns
-------
dict
A dictionary mapping field names to their parsed float values.
"""
file_header_fields = [
"firstCycleOffsetBytes",
"lineHeaderSizeBytes",
"laserPathIdx",
"bytesPerCycle",
"linesPerCycle",
"superPixelsPerCycle",
"dmdPixelsPerRow",
"dmdPixelsPerColumn",
"numChannels",
"channelMask",
"numSlices",
"channelsInterleave",
"fpgaSystemClock_Hz",
"referenceTimestamp_lower",
"referenceTimestamp_upper"
]
map = {i: field for i, field in enumerate(file_header_fields)}
struct_out = {}
for idx in range(field_value_pairs.shape[0]):
field = field_value_pairs[idx, 0]
value = field_value_pairs[idx, 1]
if field in map:
field = map[field]
struct_out[field] = float(value)
else:
print(f'Warning: Unknown field/value pair in header: fieldID={field} value={value}')
return struct_out
[docs]
def translate_channel_mask(header):
"""
A function that translates the channel mask from the header as the input. It then has various checks that validate the number of channels specified.
Parameters
----------
header : dict
Header of SLAP2 binary file read as Uint32
Returns
-------
dict
The updated header with an added 'channels' list, if validation passes.
"""
assert 'channelMask' in header
channels = [bit for bit in range(32) if (int(header['channelMask']) & (1 << bit)) != 0]
header['channels'] = channels
assert 'numChannels' in header
assert len(channels) == header['numChannels'], 'Data integrity error: header field ''numChannels'' does not agree with header field ''channelMask'''
return header
[docs]
def translate_reference_timestamp(header):
"""
Combines the lower and upper parts of the reference timestamp if they exist.
Parameters
----------
header : dict
Header dictionary containing fields like 'referenceTimestamp_lower' and 'referenceTimestamp_upper'.
Returns
-------
dict
The updated header dictionary with a combined 'referenceTimestamp' field.
"""
if 'referenceTimestamp_lower' in header and 'referenceTimestamp_upper' in header:
reference_timestamp_lower = header['referenceTimestamp_lower']
reference_timestamp_upper = int(header['referenceTimestamp_upper']) << 32
header['referenceTimestamp'] = int(reference_timestamp_lower) | reference_timestamp_upper
return header