mouseportal_device#

MousePortal stimulus device.

Launches the MousePortal infinite-corridor stimulus (a separate Panda3D app) as a subprocess and drives it with live treadmill velocity forwarded from mesofield over a localhost UDP socket. A StimulusDevice built on SubprocessStimulusDevice, which provides the launch / readiness-handshake / terminate lifecycle shared with other external-app stimulus devices. It is not a DataProducer (MousePortal writes its own per-frame CSV; this device never emits on signals.data).

Synchronisation#

mesofield owns the treadmill serial port. During arm (so the corridor is up before any camera acquires) this device subscribes to the treadmill’s signals.data and forwards each {distance, speed, device_us} sample as a UDP datagram (device_us,distance,speed) to the MousePortal process, which runs in network input mode. MousePortal logs the device_us of the latest sample on every frame, so its corridor data aligns offline to the camera timeline through the dataqueue affine fit (see mesofield.datakit.sources.behavior.mouseportal).

The matching offline parser is registered separately under the mouseportal tag in mesofield.datakit.sources; this module intentionally does not import datakit so device construction stays light.

class mesofield.devices.mouseportal_device.MousePortalDevice[source]#

Bases: SubprocessStimulusDevice

Stimulus device that launches MousePortal and feeds it treadmill velocity.

__init__(cfg)[source]#
Parameters:

cfg (Dict[str, Any])

serves_task(task, config)[source]#

Serve a task iff it matches the MousePortal config block’s task.

Each MousePortal configuration corresponds to a single task ID (a list is honored for the future multi-config case). With no task bound, MousePortal serves every task, preserving the single-stimulus behavior.

Return type:

bool

prepare(config)[source]#

Generate the MousePortal cfg.json and wire treadmill forwarding.

The output CSV path is the ExperimentConfig-authoritative path: DataManager.setup assigns self.output_path from DataPaths before arm. We fall back to config.make_path only for standalone use (no DataManager). MousePortal is handed this exact file path and writes only there – it never constructs a BIDS directory layout.

Return type:

None

build_command()[source]#

Return the full argv used to launch the stimulus subprocess.

Return type:

List[str]

launch_env()[source]#

Environment for the MousePortal subprocess.

Ensures Panda3D can find its Config.prc (which carries load-display pandagl). conda-forge’s panda3d on Windows installs the config under <env>\Library\etc\panda3d and the GL plugin under <env>\Library\bin, but Panda3D’s runtime auto-locator does not look there – so no display module loads and ShowBase aborts with “No graphics pipe is available!”. Setting PANDA_PRC_DIR points it at the right directory. Respects an existing PANDA_PRC_DIR and is a no-op when the directory cannot be found (e.g. macOS/pip layouts that already auto-locate correctly).

Return type:

Dict[str, str] | None

preflight()[source]#

Return an actionable error string if MousePortal cannot launch.

Return type:

str | None

on_stop()[source]#

Teardown for anything opened in prepare(). No-op by default.

Return type:

None

expected_experiment_duration()[source]#

Estimate the MousePortal experiment length in seconds.

Mirrors MousePortal’s per-trial resolution (condition override → global) and sums each trial’s duration plus the inter-trial interval that follows it. DURATION-ended trials are exact; DISTANCE/MANUAL trials are non-deterministic, so their per-trial trial_duration (or the global default) is used as an estimate – pair this coupling with duration-based trials for a precise camera preallocation.

Return type:

float

property calibration: Dict[str, Any]#

Record the corridor/experiment parameters with the session.