daplis_rtp.gui.file_sync_check module

Background check that both boards keep writing their files in step.

A good two-board run drops one file per board into each working directory per acquisition cycle: the same number of files on both sides, every pair created within a couple of seconds of the other. When one board stalls, drops cycles, or stops writing altogether, the two directories run off from each other - a different number of files, or a growing offset between the pairs - and the two halves can no longer be matched up afterwards, which makes the whole run useless. That can go unnoticed for hours, since the live plot of either half looks perfectly healthy on its own; hence this check.

The check runs in a thread of its own (‘FileSyncWorker’) so that listing the two directories never blocks the GUI, and reports through ‘FileSyncPanel’, a compact status box that both the full-sensor and the synchronization tab embed.

Two things are watched:

  • the file counts, which may differ - one board always creates its file a moment before the other - but only briefly, so a difference is reported only once it outlives the grace period;

  • the pairwise creation times: files are paired by their position in the time-sorted listing of each directory, so a single dropped cycle shifts every later pair and shows up at once.

Only files created after the monitoring starts are looked at: leftovers from an earlier run in the same directory would otherwise be paired with the new ones and throw every pair off.

‘st_ctime’ is the creation time on Windows, which is the platform the acquisition runs on.

class daplis_rtp.gui.file_sync_check.FileSyncPanel(parent=None, font=None, labels=('Board 1', 'Board 2'), with_paths=False)[source]

Bases: QGroupBox

Status box for the check, with the sweeping thread behind it.

The host tab calls ‘start’ when the acquisition starts and ‘stop’ when it ends; with ‘with_paths’ the box also carries its own pair of directory selectors, for tabs that do not have them already.

LED_COLORS = {'bad': 'red', 'idle': 'grey', 'ok': 'limegreen', 'pending': 'orange', 'waiting': 'goldenrod'}
__init__(parent=None, font=None, labels=('Board 1', 'Board 2'), with_paths=False)[source]
is_enabled()[source]
paths()[source]

The pair of directories the check compares.

problem

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

Type:

pyqtSignal(*types, name

set_paths(path_1, path_2)[source]

Point the check at the two working directories.

start()[source]

Begin sweeping; re-arms the alert of a previous run.

stop()[source]

End the sweep; the last verdict stays on display.

class daplis_rtp.gui.file_sync_check.FileSyncWorker(path_1, path_2, labels, baseline, tolerance=2.0, interval=5.0, grace=30.0, parent=None)[source]

Bases: QThread

Sweep both working directories until asked to stop.

Emits ‘status’ after every sweep and ‘problem’ at most once per run: the first mismatch already means the run has to be repeated, and repeating the alert every few seconds would only bury the GUI under message boxes while nobody is at the desk.

__init__(path_1, path_2, labels, baseline, tolerance=2.0, interval=5.0, grace=30.0, parent=None)[source]
problem

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

Type:

pyqtSignal(*types, name

run(self)[source]
status

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

Type:

pyqtSignal(*types, name

stop()[source]

Ask the sweep loop to end; returns without waiting for it.

class daplis_rtp.gui.file_sync_check.SyncStatus(state, text, count_1=0, count_2=0, spread=0.0)[source]

Bases: object

Outcome of one sweep, handed to the GUI thread for display.

‘state’ is one of ‘idle’, ‘waiting’ (nothing to compare yet, or a directory is missing), ‘ok’, ‘pending’ (the counts differ but the grace period has not run out) and ‘bad’.

__init__(state, text, count_1=0, count_2=0, spread=0.0)[source]
daplis_rtp.gui.file_sync_check.baseline(path_1, path_2)[source]

List what is already in both directories, as two sets of names.

Taken by the caller before the sweeping thread is started, not by the thread itself: between ‘QThread.start’ and the thread actually being scheduled, the acquisition can already have written its first file. A file landing in that window would be taken for a leftover on one board and for new data on the other, which is exactly the permanent count difference this check is meant to report.