Initial offline process implementation

Implemented the initial offline processing implementation, with
dependency layer building and ordered processing

Processing is still single threaded and unoptimized so it can take some
time to complete, the next step is to move from a single threaded design
to a ThreadPoolExecutor that splits up the buffer into a set number of
chunks for processing
This commit is contained in:
h3cx committed 2026-09-27 17:45:57 +02:00
1 parent eab0718a72
commit 6b954287a4
7 files changed
+405 -22

No files matched your search

+51 -6
View File
@@ -120,6 +120,8 @@ class Dashboard:
self.open_mode_selection()
elif key.lower() == "l":
self.load_current_stage()
elif key.lower() == "p":
self.reprocess_offline()
elif key == " ":
self.toggle_playback()
except DynaLabError as error:
@@ -132,7 +134,9 @@ class Dashboard:
if self.core.get_recording_state():
self.core.stop_recording()
self.set_message("Recording stopped; select Offline and press L to load it", "green")
self.set_message(
"Recording stopped; select Offline and press L to load it", "green"
)
else:
self.core.start_recording()
self.set_message("Recording started", "bold red")
@@ -154,7 +158,9 @@ class Dashboard:
mode = modes.get(key)
if mode is None:
self.set_message("Choose 1 Realtime, 2 Offline, 3 Playback, or Esc", "yellow")
self.set_message(
"Choose 1 Realtime, 2 Offline, 3 Playback, or Esc", "yellow"
)
return
if self.core.get_playback_state() and mode != "playback":
@@ -163,7 +169,9 @@ class Dashboard:
self.mode_selection_open = False
if mode == "offline":
self.set_message("Offline mode selected; press L to load the recording", "green")
self.set_message(
"Offline mode selected; press L to load the recording", "green"
)
elif mode == "playback":
self.set_message(
"Playback mode selected; press L to load the offline buffer", "green"
@@ -191,6 +199,14 @@ class Dashboard:
self.set_message("Select Offline or Playback before loading", "yellow")
def reprocess_offline(self) -> None:
if self.core.get_mode() != "offline":
self.set_message("Reprocessing is only available in offline mode", "yellow")
return
self.core.reprocess()
self.set_message("Offline reprocessing requested", "green")
def toggle_playback(self) -> None:
if self.core.get_mode() != "playback":
self.set_message("Switch to playback mode before pressing Space", "yellow")
@@ -252,7 +268,8 @@ class Dashboard:
controls = Text.from_markup(
"[bold]R[/bold] Record [bold]M[/bold] Choose mode "
"[bold]L[/bold] Load stage [bold]Space[/bold] Play/Pause "
"[bold]L[/bold] Load stage [bold]P[/bold] Reprocess offline "
"[bold]Space[/bold] Play/Pause "
"[bold]Q[/bold] Quit"
)
log_table = Table.grid(expand=True, padding=(0, 1))
@@ -288,7 +305,9 @@ class Dashboard:
mode_picker.add_column(width=3, style="bold cyan")
mode_picker.add_column(ratio=1)
mode_picker.add_row("1", "Realtime — receive connector data and record")
mode_picker.add_row("2", "Offline — load a completed recording into a processing buffer")
mode_picker.add_row(
"2", "Offline — load a completed recording into a processing buffer"
)
mode_picker.add_row("3", "Playback — load the offline buffer and replay it")
mode_picker.add_row("Esc", "Cancel")
panels.append(
@@ -329,6 +348,9 @@ def main() -> None:
processing_source = (
Path(__file__).with_name("process.py").read_text(encoding="utf-8")
)
processing_source_2 = (
Path(__file__).with_name("process2.py").read_text(encoding="utf-8")
)
dashboard = Dashboard(core, config, log_handler)
derive_unit = DLUnit()
@@ -357,7 +379,30 @@ def main() -> None:
),
)
derive_unit.set_data(processing_source)
core.bind_derive_unit(dlunit=derive_unit, file=None)
derive_unit_2 = DLUnit()
derive_unit_2.set_manifest(
unit_uuid=uuid4(),
input_signals=[
SignalDescriptor(
id=derive_unit._manifest.return_signal.id,
name="Input signal",
type="number",
timeout_ms=5000,
origin="derived",
)
],
return_signal=SignalDescriptor(
id=uuid4(),
name="Sq derive",
type="number",
timeout_ms=5000,
origin="derived",
),
)
derive_unit_2.set_data(processing_source_2)
core.bind_derive_unit(dlunit=derive_unit)
core.bind_derive_unit(dlunit=derive_unit_2)
try:
core.start()