Module psfdata.psfbin_sections
Classes
class HeaderSection (data: MemoryViewAbs)
-
Expand source code
class HeaderSection(Section): def __init__(self, data: MemoryViewAbs) -> None: super().__init__(data) self.props = read_properties(self._data) for k, v in self.props.items(): logger.info(f" {k}: {v}")
Helper class that provides a standard way to create an ABC using inheritance.
Ancestors
- Section
- abc.ABC
class Index (data: MemoryViewAbs)
-
Expand source code
class Index: """TypeSection has an index at the end - not strictly necessary""" def __init__(self, data: MemoryViewAbs): type = data.read_int32() assert type == 0x13 size = data.read_int32() endpos = data.abspos + size self.table = {} while data.abspos < endpos: id = data.read_int32() pos = data.read_int32() self.table[id] = pos def __str__(self) -> str: return f"Index: {self.table}"
TypeSection has an index at the end - not strictly necessary
class Section (data: MemoryViewAbs)
-
Expand source code
class Section(ABC): def __init__(self, data: MemoryViewAbs) -> None: t = data.read_int32() self.endpos = data.read_int32() classname = self.__class__.__name__ logger.info("") logger.info(f"{classname} starting at {hex(data.abspos)}, ending at {hex(self.endpos)} ({t=:#x}):") assert t == 21 self._data, self._tail = data.split_at_absolute(self.endpos)
Helper class that provides a standard way to create an ABC using inheritance.
Ancestors
- abc.ABC
Subclasses
class SimpleValueSection (data: MemoryViewAbs, typedefs: dict[int, TypeDef])
-
Expand source code
class SimpleValueSection(ValueSection): def __init__(self, data: MemoryViewAbs, typedefs: dict[int, TypeDef]) -> None: super().__init__(data) section_type = self._data.read_int32() assert section_type == 22 indexpos = self._data.read_int32() # start of the section index valuedata, indexdata = self._data.split_at_absolute(indexpos) self.values: dict[str, int | float | dict] = {} while len(valuedata): next = valuedata.read_int32(peek=True) match next: case 0x03: break # TODO... does this mean anything? case 0x10 | 0x11: id, name, value, properties = read_value_entry(valuedata, typedefs) self.values[name] = value case _: raise ValueError(f"Unknown DataType starting with: {next=}") for k, v in islice(self.values.items(), 10): logger.info(f" {k} = {str(v)[:60]}") if len(self.values) > 10: logger.info(f" ...") def get_signal(self, name: str) -> int | float | dict: return self.values[name]
Helper class that provides a standard way to create an ABC using inheritance.
Ancestors
- ValueSection
- Section
- abc.ABC
Methods
def get_signal(self, name: str) ‑> int | float | dict
-
Expand source code
def get_signal(self, name: str) -> int | float | dict: return self.values[name]
class SweepSection (data: MemoryViewAbs, typedefs: dict[int, Any])
-
Expand source code
class SweepSection(Section): def __init__(self, data: MemoryViewAbs, typedefs: dict[int, Any]) -> None: super().__init__(data) # # discard anything past endpos (TBC): # self._data = self._data[:self._data.abspos + endpos] self.sweep_def: SignalDef = read_signaldef(self._data, typedefs) # TODO: check if more than one sweep ? logger.info(f" {self.sweep_def}")
Helper class that provides a standard way to create an ABC using inheritance.
Ancestors
- Section
- abc.ABC
class SweepValueSection (data: MemoryViewAbs,
sweep_section: SweepSection,
trace_section: TraceSection,
is_windowed=False,
windowsize=4096)-
Expand source code
class SweepValueSection(ValueSection): def __init__(self, data: MemoryViewAbs, sweep_section: SweepSection, trace_section: TraceSection, is_windowed=False, windowsize=4096) -> None: super().__init__(data) self._sweep_section = sweep_section self._trace_section = trace_section if self.endpos == 0xFFFFFFFF: logger.error("Empty ValueSection (PSFXL file?)") return self.is_windowed = is_windowed self.windowsize = windowsize self.dt_pos = 0 if self.is_windowed: logger.warn("Windowed format, removing zero pad...") type = self._data.read_int32() assert type == 0x14 zeropad_size = self._data.read_int32() logger.warn(f"...removed {zeropad_size} bytes.") for i in range(zeropad_size): assert self._data.data[i] == 0 self._data = self._data[zeropad_size:] else: logger.info("Non-windowed format, creating dtype dictionary") self.complex_dtype = get_complex_dtype(self.dt_pos, sweep_section.sweep_def, trace_section.traces) def get_signal(self, name: str) -> Waveform: if self._sweep_signal is None or self._signals is None: self._sweep_signal, self._signals = self.get_data(npoints=99999999) # TODO return Waveform(self._sweep_signal, "x", self._signals[name], "y") # TODO def get_data(self, npoints: int): # this is for sweep data only swept_values = np.zeros(npoints) trace_values = {} for trace in self._trace_section.flattened(): assert isinstance(trace, SignalDef) trace_values[trace.name] = np.zeros(npoints) if self.is_windowed: points_read = 0 while points_read < npoints: chunkt = self._data.read_int32() if chunkt == 0x14: # chunk type 0x14 is filler (0xdead) l = self._data.read_int32() self._data = self._data[l:] continue d = self._data.read_int32() npoints_win = d >> 16 # for example 511 for windowsize=4096 and double type npoints_valid = d & 0xFFFF # i supect that is what the 2nd int16 means... dtype = self._sweep_section.sweep_def.dtype dtype = dtype.newbyteorder('>') # big endian data = np.frombuffer(self._data._mv, count=npoints_valid, dtype=dtype) swept_values[points_read:points_read+npoints_valid] = data self._data = self._data[npoints_win * dtype.itemsize:] for trace in self._trace_section.flattened(): self._data = self._data[8:] # what's this extra padding? (ff ff ff ff 7f ff ff ff or similar) dtype = trace.dtype dtype = dtype.newbyteorder('>') # big endian data = np.frombuffer(self._data._mv, count=npoints_valid, dtype=dtype) trace_values[trace.name][points_read:points_read+npoints_valid] = data self._data = self._data[npoints_win * dtype.itemsize:] points_read += npoints_win else: dtype = self.complex_dtype array = np.frombuffer( self._data.data, count=len(self._data) // dtype.itemsize, dtype=dtype) swept_name = self._sweep_section.sweep_def.name trace_names = list(self._trace_section.traces_by_name.keys()) swept_values = array[swept_name] trace_values = {n: array[n] for n in trace_names} # TODO complicated... return swept_values, trace_values
Helper class that provides a standard way to create an ABC using inheritance.
Ancestors
- ValueSection
- Section
- abc.ABC
Methods
def get_data(self, npoints: int)
-
Expand source code
def get_data(self, npoints: int): # this is for sweep data only swept_values = np.zeros(npoints) trace_values = {} for trace in self._trace_section.flattened(): assert isinstance(trace, SignalDef) trace_values[trace.name] = np.zeros(npoints) if self.is_windowed: points_read = 0 while points_read < npoints: chunkt = self._data.read_int32() if chunkt == 0x14: # chunk type 0x14 is filler (0xdead) l = self._data.read_int32() self._data = self._data[l:] continue d = self._data.read_int32() npoints_win = d >> 16 # for example 511 for windowsize=4096 and double type npoints_valid = d & 0xFFFF # i supect that is what the 2nd int16 means... dtype = self._sweep_section.sweep_def.dtype dtype = dtype.newbyteorder('>') # big endian data = np.frombuffer(self._data._mv, count=npoints_valid, dtype=dtype) swept_values[points_read:points_read+npoints_valid] = data self._data = self._data[npoints_win * dtype.itemsize:] for trace in self._trace_section.flattened(): self._data = self._data[8:] # what's this extra padding? (ff ff ff ff 7f ff ff ff or similar) dtype = trace.dtype dtype = dtype.newbyteorder('>') # big endian data = np.frombuffer(self._data._mv, count=npoints_valid, dtype=dtype) trace_values[trace.name][points_read:points_read+npoints_valid] = data self._data = self._data[npoints_win * dtype.itemsize:] points_read += npoints_win else: dtype = self.complex_dtype array = np.frombuffer( self._data.data, count=len(self._data) // dtype.itemsize, dtype=dtype) swept_name = self._sweep_section.sweep_def.name trace_names = list(self._trace_section.traces_by_name.keys()) swept_values = array[swept_name] trace_values = {n: array[n] for n in trace_names} # TODO complicated... return swept_values, trace_values
def get_signal(self, name: str) ‑> Waveform
-
Expand source code
def get_signal(self, name: str) -> Waveform: if self._sweep_signal is None or self._signals is None: self._sweep_signal, self._signals = self.get_data(npoints=99999999) # TODO return Waveform(self._sweep_signal, "x", self._signals[name], "y") # TODO
class TraceIndex (data: MemoryViewAbs)
-
Expand source code
class TraceIndex: def __init__(self, data: MemoryViewAbs): self.type = data.read_int32() assert self.type == 0x13 self.size = data.read_int32() endpos = data.abspos + self.size self.table = defaultdict(list) while data.abspos < endpos: id = data.read_bytes(4).rstrip(b'\x00').decode() offset = data.read_int32() extra1 = data.read_int32() extra2 = data.read_int32() if id: # most entries are empty (?) self.table[id].append(offset) def __str__(self) -> str: return f"Index: {dict(self.table)}"
class TraceSection (data: MemoryViewAbs, typedefs: dict[int, TypeDef])
-
Expand source code
class TraceSection(Section): """identical to TypeSection, except datatypes are references and index is a TraceIndex...""" traces: dict[int, SignalDef | Group] traces_by_name: dict[str, SignalDef] def __init__(self, data: MemoryViewAbs, typedefs: dict[int, TypeDef]) -> None: super().__init__(data) section_type = self._data.read_int32() assert section_type == 22 indexpos = self._data.read_int32() # start of the section index tracedata, indexdata = self._data.split_at_absolute(indexpos) self.traces = {} self.traces_by_name = {} while len(tracedata): next = tracedata.read_int32(peek=True) match next: case 0x03: break # TODO... does this mean anything? case 0x10 | 0x11: signaldef = read_signaldef(tracedata, typedefs=typedefs) self.traces[signaldef.id] = signaldef # TODO: do we really want to flatten groups if isinstance(signaldef, Group): for c in signaldef.children: self.traces_by_name[c.name] = c else: self.traces_by_name[signaldef.name] = signaldef case _: raise ValueError(f"Unknown DataType starting with: {next=}") self.index = TraceIndex(indexdata) for k, v in self.traces_by_name.items(): logger.info(f" {str(v)[:100]}") if isinstance(v, Group): for c in v.children: logger.info(f" {str(c)[:96]}") def flattened(self) -> Generator[SignalDef, None, None]: for dt in self.traces.values(): if isinstance(dt, Group): yield from dt.children else: yield dt
identical to TypeSection, except datatypes are references and index is a TraceIndex…
Ancestors
- Section
- abc.ABC
Class variables
var traces : dict[int, SignalDef | Group]
-
The type of the None singleton.
var traces_by_name : dict[str, SignalDef]
-
The type of the None singleton.
Methods
def flattened(self) ‑> Generator[SignalDef, None, None]
-
Expand source code
def flattened(self) -> Generator[SignalDef, None, None]: for dt in self.traces.values(): if isinstance(dt, Group): yield from dt.children else: yield dt
class TypeSection (data: MemoryViewAbs)
-
Expand source code
class TypeSection(Section): def __init__(self, data: MemoryViewAbs) -> None: super().__init__(data) section_type = self._data.read_int32() assert section_type == 22 indexpos = self._data.read_int32() # start of the section index typedata, indexdata = self._data.split_at_absolute(indexpos) self.typedefs: dict[int, TypeDef] = {} self.read_typedefs(typedata) for v in self.typedefs.values(): logger.info(f" {v}") if v.struct_members is not None: for c in v.struct_members[:10]: logger.info(f" {c}") if len(v.struct_members) > 10: logger.info(f" ...") self.index = Index(indexdata) def read_typedefs(self, data: MemoryViewAbs) -> None: while len(data): next = data.read_int32(peek=True) match next: case 0x03: return # TODO... does this mean anything? case 0x10 | 0x11: element = read_typedef(data) self.typedefs[element.id] = element case _: raise ValueError(f"Unknown DataType starting with: {next=}")
Helper class that provides a standard way to create an ABC using inheritance.
Ancestors
- Section
- abc.ABC
Methods
def read_typedefs(self, data: MemoryViewAbs) ‑> None
-
Expand source code
def read_typedefs(self, data: MemoryViewAbs) -> None: while len(data): next = data.read_int32(peek=True) match next: case 0x03: return # TODO... does this mean anything? case 0x10 | 0x11: element = read_typedef(data) self.typedefs[element.id] = element case _: raise ValueError(f"Unknown DataType starting with: {next=}")
class ValueSection (data: MemoryViewAbs)
-
Expand source code
class ValueSection(Section): def __init__(self, data: MemoryViewAbs) -> None: super().__init__(data) self._names: list[str] = [] @property def sweep_info(self) -> dict[str, Any] | None: return None @property def names(self) -> list[str]: return self._names @abstractmethod def get_signal(self, name: str) -> Waveform | dict: raise NotImplementedError()
Helper class that provides a standard way to create an ABC using inheritance.
Ancestors
- Section
- abc.ABC
Subclasses
Instance variables
prop names : list[str]
-
Expand source code
@property def names(self) -> list[str]: return self._names
prop sweep_info : dict[str, Any] | None
-
Expand source code
@property def sweep_info(self) -> dict[str, Any] | None: return None
Methods
def get_signal(self, name: str) ‑> Waveform | dict
-
Expand source code
@abstractmethod def get_signal(self, name: str) -> Waveform | dict: raise NotImplementedError()