Updated docs and updated API to fetch signal descriptors in all modes
API and Protocol docs have been updated (GPT 5.6) The API methods for fetching a sepcific signal descriptor and fetching all signal descriptors now work in offline mode, the core_tui.py example has been updated to fit the new tri mode architecture and loading recording offload -> processing and then processing -> playback engine all works
This commit is contained in:
6 files changed
+356
-596
No files matched your search
+80
-29
@@ -102,6 +102,8 @@ class Dashboard:
|
||||
self.config = config
|
||||
self.log_handler = log_handler
|
||||
self.running = True
|
||||
self.mode_selection_open = False
|
||||
self.offline_loaded = False
|
||||
self.playback_loaded = False
|
||||
self.message = "Waiting for a connector"
|
||||
self.message_style = "dim"
|
||||
@@ -110,12 +112,14 @@ class Dashboard:
|
||||
try:
|
||||
if key.lower() == "q":
|
||||
self.running = False
|
||||
elif self.mode_selection_open:
|
||||
self.select_mode(key)
|
||||
elif key.lower() == "r":
|
||||
self.toggle_recording()
|
||||
elif key.lower() == "m":
|
||||
self.toggle_mode()
|
||||
self.open_mode_selection()
|
||||
elif key.lower() == "l":
|
||||
self.load_playback()
|
||||
self.load_current_stage()
|
||||
elif key == " ":
|
||||
self.toggle_playback()
|
||||
except DynaLabError as error:
|
||||
@@ -128,35 +132,64 @@ class Dashboard:
|
||||
|
||||
if self.core.get_recording_state():
|
||||
self.core.stop_recording()
|
||||
self.set_message("Recording stopped and prepared for playback", "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")
|
||||
|
||||
def toggle_mode(self) -> None:
|
||||
def open_mode_selection(self) -> None:
|
||||
if self.core.get_recording_state():
|
||||
self.set_message("Stop recording before changing mode", "yellow")
|
||||
return
|
||||
|
||||
if self.core.get_mode() == "realtime":
|
||||
self.core.set_mode("playback")
|
||||
self.set_message(
|
||||
"Playback mode selected; press L to load a recording", "green"
|
||||
)
|
||||
else:
|
||||
if self.core.get_playback_state():
|
||||
self.core.pause()
|
||||
self.core.set_mode("realtime")
|
||||
self.set_message("Realtime mode selected", "green")
|
||||
self.mode_selection_open = True
|
||||
self.set_message("Choose a mode: 1 Realtime, 2 Offline, 3 Playback", "cyan")
|
||||
|
||||
def load_playback(self) -> None:
|
||||
if self.core.get_mode() != "playback":
|
||||
self.set_message("Switch to playback mode before loading", "yellow")
|
||||
def select_mode(self, key: str) -> None:
|
||||
modes = {"1": "realtime", "2": "offline", "3": "playback"}
|
||||
if key == "\x1b" or key.lower() == "m":
|
||||
self.mode_selection_open = False
|
||||
self.set_message("Mode selection cancelled", "dim")
|
||||
return
|
||||
|
||||
self.core.load_playback_engine()
|
||||
self.playback_loaded = True
|
||||
self.set_message("Internal processing buffer loaded", "green")
|
||||
mode = modes.get(key)
|
||||
if mode is None:
|
||||
self.set_message("Choose 1 Realtime, 2 Offline, 3 Playback, or Esc", "yellow")
|
||||
return
|
||||
|
||||
if self.core.get_playback_state() and mode != "playback":
|
||||
self.core.pause()
|
||||
self.core.set_mode(mode)
|
||||
self.mode_selection_open = False
|
||||
|
||||
if mode == "offline":
|
||||
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"
|
||||
)
|
||||
else:
|
||||
self.set_message("Realtime mode selected", "green")
|
||||
|
||||
def load_current_stage(self) -> None:
|
||||
mode = self.core.get_mode()
|
||||
if mode == "offline":
|
||||
self.core.load_processing_buffer()
|
||||
self.offline_loaded = True
|
||||
self.playback_loaded = False
|
||||
self.set_message(
|
||||
"Recording loaded into the offline buffer; select Playback and press L",
|
||||
"green",
|
||||
)
|
||||
return
|
||||
|
||||
if mode == "playback":
|
||||
self.core.load_playback_engine()
|
||||
self.playback_loaded = True
|
||||
self.set_message("Offline buffer loaded into playback", "green")
|
||||
return
|
||||
|
||||
self.set_message("Select Offline or Playback before loading", "yellow")
|
||||
|
||||
def toggle_playback(self) -> None:
|
||||
if self.core.get_mode() != "playback":
|
||||
@@ -190,8 +223,8 @@ class Dashboard:
|
||||
style="bold red" if recording else "dim",
|
||||
),
|
||||
Text(
|
||||
self.playback_status(playing),
|
||||
style="bold green" if playing else "dim",
|
||||
self.buffer_status(mode, playing),
|
||||
style="bold green" if playing or self.offline_loaded else "dim",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -218,8 +251,8 @@ class Dashboard:
|
||||
value_table.add_row("Waiting for connector…", "", "—", "")
|
||||
|
||||
controls = Text.from_markup(
|
||||
"[bold]R[/bold] Record [bold]M[/bold] Mode "
|
||||
"[bold]L[/bold] Load [bold]Space[/bold] Play/Pause "
|
||||
"[bold]R[/bold] Record [bold]M[/bold] Choose mode "
|
||||
"[bold]L[/bold] Load stage [bold]Space[/bold] Play/Pause "
|
||||
"[bold]Q[/bold] Quit"
|
||||
)
|
||||
log_table = Table.grid(expand=True, padding=(0, 1))
|
||||
@@ -239,7 +272,7 @@ class Dashboard:
|
||||
for _ in range(VISIBLE_LOG_LINES - max(1, len(log_entries))):
|
||||
log_table.add_row("", "", "")
|
||||
|
||||
return Group(
|
||||
panels = [
|
||||
Panel(
|
||||
status,
|
||||
title="DynaLab Core",
|
||||
@@ -249,19 +282,37 @@ class Dashboard:
|
||||
Panel(value_table, title="Live values", border_style="cyan"),
|
||||
Panel(Text(self.message, style=self.message_style), title="Status"),
|
||||
Panel(controls, title="Hotkeys", border_style="blue"),
|
||||
]
|
||||
if self.mode_selection_open:
|
||||
mode_picker = Table.grid(expand=True, padding=(0, 2))
|
||||
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("3", "Playback — load the offline buffer and replay it")
|
||||
mode_picker.add_row("Esc", "Cancel")
|
||||
panels.append(
|
||||
Panel(mode_picker, title="Choose mode", border_style="yellow")
|
||||
)
|
||||
panels.append(
|
||||
Panel(
|
||||
log_table,
|
||||
title=f"Logs · latest {VISIBLE_LOG_LINES}",
|
||||
border_style="magenta",
|
||||
),
|
||||
)
|
||||
)
|
||||
return Group(*panels)
|
||||
|
||||
def playback_status(self, playing: bool) -> str:
|
||||
def buffer_status(self, mode: str, playing: bool) -> str:
|
||||
if playing:
|
||||
return "Playback: PLAYING"
|
||||
if self.playback_loaded:
|
||||
if mode == "playback" and self.playback_loaded:
|
||||
return "Playback: LOADED"
|
||||
return "Playback: NOT LOADED"
|
||||
if mode == "offline" and self.offline_loaded:
|
||||
return "Offline: LOADED"
|
||||
if self.offline_loaded:
|
||||
return "Offline buffer: READY"
|
||||
return "Offline buffer: NOT LOADED"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
Reference in new issue
Block a user