Python API Reference

This section provides detailed documentation for the microsync Python API.

Core Classes

class Event(c_struct_data)[source]

Bases: object

Represents a scheduled event in the device’s priority queue.

This class contains all the information needed to execute an event, including the function to call, its arguments, timing, and repetition parameters.

func

Function name to execute

Type:

str

arg1

First argument (usually pin number)

arg2

Second argument (usually level or duration)

ts

Timestamp when to execute the event (in specified units)

Type:

int

N

Number of remaining event repetitions

Type:

int

intvl

Interval between event repetitions

Type:

int

unit

Time unit (“cts”, “us”, or “ms”)

Type:

str

__init__(c_struct_data)[source]

Create an Event from raw C structure data.

Parameters:

c_struct_data (bytes) – 28-byte C structure data from device

map_func(func_map)[source]

Map the function address to the corresponding function name. This is used to convert the function address returned by the device to the corresponding function name for pretty printing of the event table.

class SyncDevice(port, log_file=None)[source]

Bases: object

Python interface for 32-bit microscope synchronization device.

This class provides a high-level API for controlling the Arduino Due-based synchronization device. It handles communication, event scheduling, and provides convenient methods for common microscope control tasks.

The device supports microsecond-precision event scheduling with a priority queue system, laser shutter control, and various acquisition modes.

com

Serial communication interface

func_map

Mapping of function addresses from device

_pending_tx_

Buffer for context manager commands

_in_context

Context manager state flag

Note

Opening the port and connecting to the sync device resets the device.

Example

>>> sd = SyncDevice("COM4")
>>> sd.pos_pulse("A0", 1000, N=10, interval=50000)
>>> sd.go()
property N_events

Get the number of scheduled events in the event queue.

Returns:

Number of events currently in the queue

Return type:

int

N_frames_left()[source]

Get the number of camera frames remaining in the current acquisition.

Returns:

Number of camera frames left to acquire, or 0 if no acquisition is running

Return type:

int

Note

In the ALEX mode, the number of frames left to acquire is the number of remaining bursts times the number of laser channels.

Example

>>> frames_left = sd.N_frames_left()
>>> print(f"Remaining frames: {frames_left}")
__enter__()[source]

Enter context manager for batch command transmission.

After entering the context manager, commands sent to the device are not transmitted immediately. Instead, they are queued and transmitted as a single batch when exiting the context manager.

Example

>>> with sd as dev:
...     dev.pos_pulse("A0", 1000, ts=0)
...     dev.pos_pulse("A1", 1000, ts=5000)
__exit__(*args, **kwargs)[source]

Exit context manager and transmit batched commands.

All commands collected within the context manager are sent as a single data packet to ensure precise timing and eliminate host OS jitter.

__init__(port, log_file=None)[source]

Initialize connection to the sync device and reset it.

Parameters:
  • port (str) – Serial port name (e.g., “COM4”, “/dev/ttyUSB0”)

  • log_file (str, optional) – Logging configuration: - None: No logging - “print”: Print to terminal - filename: Save to file

Raises:

Example

>>> sd = SyncDevice("COM4", log_file="sync.log")
>>> sd = SyncDevice("/dev/ttyUSB0", log_file="print")
property cam_readout_us

Get the pre-programmed camera readout time.

Returns:

Pre-set camera readout time in microseconds

Return type:

int

clear()[source]

Clear all scheduled events from the event queue.

This method removes all pending events from the event queue. The system timer is not affected and keeps running - use stop() to halt processing and reset the timer.

Example

>>> sd.clear()  # Remove all scheduled events
close_shutters(mask=0)[source]

Close all laser shutters. Use the mask argument to specify which shutters to close. Omitting the mask argument will close all shutters.

Parameters:

mask (int) –

Bitmask specifying which shutters to close:

  • 0: Closes all shutters (note: This differs from the behavior of the mask in the selected_lasers property.)

  • 1: Cy2 only

  • 2: Cy3 only

  • 4: Cy5 only

  • 8: Cy7 only

  • Combinations: 1|2|4 = Cy2, Cy3, and Cy5

Example

>>> sd.close_shutters()   # Close all shutters
>>> sd.close_shutters(2)  # Close Cy3 only
disable_pin(pin, ts=0, N=0, interval=0)[source]

Disable a pin output. The previous logical value of the pin is preserved.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.disable_pin("A0", ts=1000)  # Disable A0 after 1ms
enable_pin(pin, ts=0, N=0, interval=0)[source]

Enable a pin, setting it as active. The logical level of the pin is preserved.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.disable_pin("A0")  # Disable A0. It will stay low regardless of calls to set_pin()
>>> sd.set_pin("A0", 1)   # Set A0 high. It will still stay low as the pin is disabled
>>> sd.enable_pin("A0", ts=1000)  # Enable A0 after 1ms. It will restore logical high level set by the previous call to set_pin()
get_events(unit='ms')[source]

Get all scheduled events from the device queue.

Parameters:

unit (str) – Time unit for timestamps (“cts”, “us”, or “ms”)

Returns:

List of Event objects representing scheduled events

Return type:

list

Example

>>> events = sd.get_events("us")
>>> for event in events:
...     print(f"{event.func} at {event.ts} {event.unit}")
get_function_addr()[source]

Get the function address mapping from the device.

Returns:

Mapping of function names to their addresses

Return type:

dict

Note

This is used internally to map function addresses to readable names.

get_property(prop)[source]

Get a device property value; if the property is write-only, it will return an error.

Parameters:

prop – Property enum or integer ID, see props.h for available properties

Returns:

Property value as string

Return type:

str

Example

>>> version = sd.get_property(props.ro_VERSION)
get_status()[source]

Get detailed system status information.

The status report includes the following information: - Firmware version - System status header - Number of events in the event queue - System timer status (RUNNING or STOPPED) - System time in seconds

Example

>>> status = sd.get_status()
>>> print(status)
go()[source]

Start the system timer and begin processing scheduled events.

This method starts the hardware timer that processes the event queue. All scheduled events will be called exactly at their specified timestamps.

If more than one event is scheduled at the same time, their order of execution is undefined.

Example

>>> sd.pos_pulse("A0", 1000, ts=1000)  # Sends positive pulse 1ms after go() is called
>>> sd.go()  # Start processing events
property interlock_enabled

Check if the laser interlock is enabled. The interlock is a safety feature that prevents the laser from being turned on if the interlock circuit is broken. By default, the interlock is active.

Returns:

True if interlock is active, False otherwise

Return type:

bool

neg_pulse(pin, duration=0, ts=0, N=0, interval=0)[source]

Generate a negative pulse on a pin. Attempting to generate a pulse on a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • duration (int) – Pulse duration (in microseconds)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.neg_pulse("A0", 1000, ts=5000, N=10, interval=50000)
open_shutters(mask=0)[source]

Open all laser shutters. Use the mask argument to specify which shutters to open. Omitting the mask argument will open all shutters.

Parameters:

mask (int) –

Bitmask specifying which shutters to open:

  • 0: Opens all shutters (note: This differs from the behavior of the mask in the selected_lasers property.)

  • 1: Cy2 only

  • 2: Cy3 only

  • 4: Cy5 only

  • 8: Cy7 only

  • Combinations: 1|2|4 = Cy2, Cy3, and Cy5

Example

>>> sd.open_shutters()  # Open all shutters
>>> sd.open_shutters(1 | 4)  # Open Cy2 and Cy5 only
pos_pulse(pin, duration=0, ts=0, N=0, interval=0)[source]

Generate a positive pulse on a pin. Attempting to generate a pulse on a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • duration (int) – Pulse duration (in microseconds)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.pos_pulse("A0", 1000, ts=5000, N=10, interval=50000)
property prescaler

Get the sync device timer prescaler value. The Arduino Due runs at 84 MHz, and the system timer is clocked at 84 MHz / prescaler. The prescaler defines the system time resolution (duration of one tick, ranging from 24 ns to 1.524 µs), as well as the maximum allowable timestamp value \(t_\mathrm{max}\) (\(2^{32}\) ticks).

\(t_\mathrm{max}\) is defined as \(2^{32} \cdot \mathrm{prescaler} / 84\) µs, and ranges from 1min 42s to 1h 49min.

Returns:

Timer prescaler (2, 8, 32, or 128)

Return type:

int

Note

The prescaler is hardcoded in the firmware, and cannot be changed at runtime.

See globals.h for the prescaler values and their corresponding system time resolution and maximum timestamp value.

property pulse_duration_us

Get the default pulse duration in microseconds. The default pulse duration is the duration of a positive or negative pulse generated by the pos_pulse() and neg_pulse() methods, and can be changed at runtime.

Returns:

Default pulse duration in microseconds

Return type:

int

pulse_train(period, duration=0, ts=0, N=0, interval=0)[source]

Generate a burst of pulses.

Parameters:
  • period (int) – Period between pulses (in microseconds)

  • duration (int) – Duration of each pulse (in microseconds)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.pulse_train(1000, 100, ts=0, N=1000)  # 1000 pulses, 1kHz
query(cmd, arg1=0, arg2=0, ts=0, N=0, interval=0)[source]

Query the sync device - write a command and read the reply.

Parameters:

cmd (str)

reset()[source]

Reset the sync device and clear all events.

This method performs a soft reset of the device, clearing all events and resetting system parameters to their default values. A “soft reset” triggers a processor reset via software by writing a key and command to the Reset Controller (RSTC), which restarts the CPU without cycling power or affecting external peripherals.

Note

This operation will immediately stop the running hardware system timer, clear the event queue, and restart the device firmware. All scheduled events and timer state will be lost, and the device will reboot to its initial state, and send a startup message, indicating the firmware version.

Example

>>> sd.reset()  # Reset device to default state
property running

Check whether the sync device system timer is running.

Returns:

True if system timer is active, False otherwise

Return type:

bool

property selected_lasers

Get the currently enabled laser channels.

Returns:

Bitmask of enabled laser channels

Return type:

int

Example

>>> mask = sd.selected_lasers
>>> print(f"Enabled lasers: {bin(mask)}")
set_pin(pin, level, ts=0, N=0, interval=0)[source]

Set a pin to a specific logical level. Attempting to set a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • level (int) – Pin level (0=low, 1=high)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.set_pin("A0", 1, ts=1000)  # Set A0 high after 1ms
set_property(prop, value)[source]

Set a device property value; if the property is read-only, it will return an error.

Parameters:
  • prop – Property enum or integer ID, see props.h for available properties

  • value – New property value

Example

>>> sd.set_property(props.rw_DFLT_PULSE_DURATION_us, 1000)
property shutter_delay_us

Get the pre-programmed laser shutter delay time.

Returns:

Shutter delay time in microseconds

Return type:

int

start_ALEX_acq(exp_time, N_bursts, ts=0, burst_period=0)[source]

Start ALEX (Alternating Laser Excitation) acquisition.

In ALEX mode, frames are acquired in bursts, with each frame in a burst illuminated by a different laser channel. This enables multi-spectral imaging, and is useful for acquiring images of multiple fluorophores with different emission wavelengths.

Parameters:
  • exp_time (int) – Exposure time in microseconds

  • N_bursts (int) – Number of bursts to acquire

  • ts (int) – Start time offset in microseconds

  • burst_period (int) – Time between bursts for timelapse (microseconds)

Example

>>> sd.start_ALEX_acq(50000, 9, burst_period=400000)
start_continuous_acq(exp_time, N_frames, ts=0)[source]

Start continuous acquisition mode.

In continuous mode, laser shutters remain open during the entire acquisition and the camera is triggered at precise intervals. The first frame is automatically discarded as it contains pre-acquisition noise.

Parameters:
  • exp_time (int) – Exposure time in microseconds

  • N_frames (int) – Number of frames to acquire

  • ts (int) – Start time offset in microseconds

Example

>>> sd.start_continuous_acq(200000, 15, ts=500000)  # Acquire 15 frames with 200ms exposure, start at t=500ms
start_stroboscopic_acq(exp_time, N_frames, ts=0, frame_period=0)[source]

Start stroboscopic or timelapse acquisition.

In stroboscopic mode, the laser shutter is briefly opened during each camera exposure, followed by a readout period. The interval between frames is set by the optional frame_period parameter, which can be used to add a delay between laser pulses for timelapse acquisition.

Parameters:
  • exp_time (int) – Exposure time in microseconds

  • N_frames (int) – Number of frames to acquire

  • ts (int) – Start time offset in microseconds

  • frame_period (int) – Time between frames for timelapse (microseconds)

Example

>>> # Acquire 10 frames every 500ms with 100ms long laser exposure (timelapse mode)
>>> sd.start_stroboscopic_acq(100000, 10, frame_period=500000)
stop()[source]

Stop the sync device system timer and halt event processing.

This method stops and resets the hardware timer, and deletes the event queue.

Example

>>> sd.stop()  # Pause event processing
>>> # schedule some events
>>> sd.go()    # Start processing events (from t=0)
property sys_time_cts

Get current sync device system time in counter ticks.

Returns:

64-bit system time in counter ticks

Return type:

int

property sys_time_s

Get current sync device system time in seconds.

Returns:

System time in seconds

Return type:

float

tgl_pin(pin, ts=0, N=0, interval=0)[source]

Toggle a pin state. Attempting to toggle a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.tgl_pin("D13", N=1000, interval=1000)  # Toggle D13 every 1ms
property version

Get the firmware version. The version is a string of the form “X.Y.Z”, where X=major, Y=minor, and Z=patch. The major and minor version number of the firmware and the driver must match.

Returns:

Firmware version string (e.g., “2.4.0”)

Return type:

str

property watchdog_timeout_ms

Get the watchdog timeout value in milliseconds. The watchdog is a safety feature that resets the sync device if it stops responding for a certain amount of time. This can happen i.e. if too many events are scheduled, and the sync device is not managing to process them in a timely manner.

Returns:

Watchdog timeout in milliseconds, 100 ms by default

Return type:

int

write(cmd, arg1=0, arg2=0, ts=0, N=0, interval=0)[source]

Send a command to the synchronization device. If the device is in a context manager, the command is queued and transmitted as a single batch when exiting the context manager. If the device is not in a context manager, the command is transmitted immediately.

Parameters:
  • cmd (str) – 3-character command code

  • arg1 – First argument (can be string or integer)

  • arg2 (int) – Second argument

  • ts (int) – Timestamp (in microseconds)

  • N (int) – Number of event repetitions

  • interval (int) – Interval between event repetitions (in microseconds)

Note

This is a low-level method. For most applications, use the high-level methods like pos_pulse(), tgl_pin(), etc.

class props(value)[source]

Bases: Enum

Enum class for the properties of the sync device. See corresponding enum in props.h

ro_N_EVENTS = 8

Number of events in queue (read-only)

ro_SYS_TIMER_OVF_COUNT = 3

System timer overflow count (read-only)

ro_SYS_TIMER_PRESCALER = 5

System timer prescaler value (read-only)

ro_SYS_TIMER_STATUS = 1

System timer running status (read-only)

ro_SYS_TIMER_VALUE = 2

Current system timer value (read-only)

ro_SYS_TIME_s = 4

Current system time in seconds (read-only)

ro_VERSION = 0

Device version number (read-only)

ro_WATCHDOG_TIMEOUT_ms = 7

Watchdog timeout in milliseconds (read-only)

rw_CAM_READOUT_us = 14

Camera readout time in microseconds (read-write)

rw_DFLT_PULSE_DURATION_us = 6

Default pulse duration in microseconds (read-write)

rw_INTLCK_ENABLED = 9

Laser interlock enabled state (read-write)

rw_SELECTED_LASERS = 10

Selected laser mask (read-write)

rw_SHUTTER_DELAY_us = 13

Shutter delay in microseconds (read-write)

wo_CLOSE_SHUTTERS = 12

Close all shutters (write-only)

wo_OPEN_SHUTTERS = 11

Open all shutters (write-only)

Modules

Constants module for microsync Python driver.

This module defines fundamental constants used throughout the microsync Python driver, including time units, frequency units, and device-specific configuration values.

Constants:

ms: Time unit for milliseconds (0.001 seconds) us: Time unit for microseconds (0.001 milliseconds) kHz: Frequency unit for kilohertz (1000 Hz) MHz: Frequency unit for megahertz (1000 kHz) UNIFORM_TIME_DELAY: Default uniform time delay in microseconds BAUDRATE: UART communication baud rate

BAUDRATE = 115200

UART communication baud rate for device communication.

MHz = 1000000

Megahertz frequency unit (1000 kHz).

UNIFORM_TIME_DELAY = 500

Default uniform time delay in microseconds for event scheduling.

kHz = 1000

Kilohertz frequency unit (1000 Hz).

ms = 0.001

Millisecond time unit (0.001 seconds).

us = 1e-06

Microsecond time unit (0.001 milliseconds).

Reverse pin mapping for microsync Python driver.

This module provides a reverse mapping from internal pin IDs to human-readable Arduino Due pin names. The mapping converts the device’s internal pin numbering system to the familiar Arduino pin names (D0-D65, A0-A15).

The reverse pin map is used for: - Converting internal pin IDs to readable names in error messages - Providing user-friendly pin identification in logs and debugging - Maintaining compatibility with Arduino pin naming conventions

Note

This mapping is specific to the Arduino Due board and the SAM3X8E microcontroller pin configuration used in microsync.

rev_pin_map = {0: 'A15', 1: 'A14', 2: 'A7', 3: 'A6', 4: 'A5', 6: 'A4', 7: 'D31', 8: 'D0', 9: 'D1', 10: 'D19', 11: 'D18', 12: 'D17', 13: 'D16', 14: 'D23', 15: 'D24', 16: 'A0', 19: 'D42', 20: 'D43', 22: 'A3', 23: 'A2', 24: 'A1', 28: 'D10', 29: 'D4', 44: 'D20', 45: 'D21', 46: 'D53', 47: 'A12', 48: 'A13', 49: 'A8', 50: 'A9', 51: 'A10', 52: 'A11', 53: 'D52', 57: 'D2', 58: 'D22', 59: 'D13', 65: 'D33', 66: 'D34', 67: 'D35', 68: 'D36', 69: 'D37', 70: 'D38', 71: 'D39', 72: 'D40', 73: 'D41', 76: 'D51', 77: 'D50', 78: 'D49', 79: 'D48', 80: 'D47', 81: 'D46', 82: 'D45', 83: 'D44', 85: 'D9', 86: 'D8', 87: 'D7', 88: 'D6', 89: 'D5', 92: 'D3', 96: 'D25', 97: 'D26', 98: 'D27', 99: 'D28', 100: 'D14', 101: 'D15', 102: 'D29', 103: 'D11', 104: 'D12', 105: 'D30', 106: 'D32'}

Reverse mapping from internal pin IDs to Arduino Due pin names.

This dictionary maps the device’s internal pin IDs to human-readable Arduino Due pin names. The mapping includes: - Digital pins D0 through D65 - Analog pins A0 through A15

The internal pin IDs are based on the SAM3X8E microcontroller’s port and pin numbering system, while the Arduino names follow the standard Arduino Due pinout convention.

Example

>>> rev_pin_map[8]
'D0'
>>> rev_pin_map[16]
'A0'

__version__.py

Information about the current version of package

Utility Functions

class Event(c_struct_data)[source]

Represents a scheduled event in the device’s priority queue.

This class contains all the information needed to execute an event, including the function to call, its arguments, timing, and repetition parameters.

func

Function name to execute

Type:

str

arg1

First argument (usually pin number)

arg2

Second argument (usually level or duration)

ts

Timestamp when to execute the event (in specified units)

Type:

int

N

Number of remaining event repetitions

Type:

int

intvl

Interval between event repetitions

Type:

int

unit

Time unit (“cts”, “us”, or “ms”)

Type:

str

__init__(c_struct_data)[source]

Create an Event from raw C structure data.

Parameters:

c_struct_data (bytes) – 28-byte C structure data from device

map_func(func_map)[source]

Map the function address to the corresponding function name. This is used to convert the function address returned by the device to the corresponding function name for pretty printing of the event table.

class SyncDevice(port, log_file=None)[source]

Python interface for 32-bit microscope synchronization device.

This class provides a high-level API for controlling the Arduino Due-based synchronization device. It handles communication, event scheduling, and provides convenient methods for common microscope control tasks.

The device supports microsecond-precision event scheduling with a priority queue system, laser shutter control, and various acquisition modes.

com

Serial communication interface

func_map

Mapping of function addresses from device

_pending_tx_

Buffer for context manager commands

_in_context

Context manager state flag

Note

Opening the port and connecting to the sync device resets the device.

Example

>>> sd = SyncDevice("COM4")
>>> sd.pos_pulse("A0", 1000, N=10, interval=50000)
>>> sd.go()
property N_events

Get the number of scheduled events in the event queue.

Returns:

Number of events currently in the queue

Return type:

int

N_frames_left()[source]

Get the number of camera frames remaining in the current acquisition.

Returns:

Number of camera frames left to acquire, or 0 if no acquisition is running

Return type:

int

Note

In the ALEX mode, the number of frames left to acquire is the number of remaining bursts times the number of laser channels.

Example

>>> frames_left = sd.N_frames_left()
>>> print(f"Remaining frames: {frames_left}")
__enter__()[source]

Enter context manager for batch command transmission.

After entering the context manager, commands sent to the device are not transmitted immediately. Instead, they are queued and transmitted as a single batch when exiting the context manager.

Example

>>> with sd as dev:
...     dev.pos_pulse("A0", 1000, ts=0)
...     dev.pos_pulse("A1", 1000, ts=5000)
__exit__(*args, **kwargs)[source]

Exit context manager and transmit batched commands.

All commands collected within the context manager are sent as a single data packet to ensure precise timing and eliminate host OS jitter.

__init__(port, log_file=None)[source]

Initialize connection to the sync device and reset it.

Parameters:
  • port (str) – Serial port name (e.g., “COM4”, “/dev/ttyUSB0”)

  • log_file (str, optional) – Logging configuration: - None: No logging - “print”: Print to terminal - filename: Save to file

Raises:

Example

>>> sd = SyncDevice("COM4", log_file="sync.log")
>>> sd = SyncDevice("/dev/ttyUSB0", log_file="print")
property cam_readout_us

Get the pre-programmed camera readout time.

Returns:

Pre-set camera readout time in microseconds

Return type:

int

clear()[source]

Clear all scheduled events from the event queue.

This method removes all pending events from the event queue. The system timer is not affected and keeps running - use stop() to halt processing and reset the timer.

Example

>>> sd.clear()  # Remove all scheduled events
close_shutters(mask=0)[source]

Close all laser shutters. Use the mask argument to specify which shutters to close. Omitting the mask argument will close all shutters.

Parameters:

mask (int) –

Bitmask specifying which shutters to close:

  • 0: Closes all shutters (note: This differs from the behavior of the mask in the selected_lasers property.)

  • 1: Cy2 only

  • 2: Cy3 only

  • 4: Cy5 only

  • 8: Cy7 only

  • Combinations: 1|2|4 = Cy2, Cy3, and Cy5

Example

>>> sd.close_shutters()   # Close all shutters
>>> sd.close_shutters(2)  # Close Cy3 only
disable_pin(pin, ts=0, N=0, interval=0)[source]

Disable a pin output. The previous logical value of the pin is preserved.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.disable_pin("A0", ts=1000)  # Disable A0 after 1ms
enable_pin(pin, ts=0, N=0, interval=0)[source]

Enable a pin, setting it as active. The logical level of the pin is preserved.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.disable_pin("A0")  # Disable A0. It will stay low regardless of calls to set_pin()
>>> sd.set_pin("A0", 1)   # Set A0 high. It will still stay low as the pin is disabled
>>> sd.enable_pin("A0", ts=1000)  # Enable A0 after 1ms. It will restore logical high level set by the previous call to set_pin()
get_events(unit='ms')[source]

Get all scheduled events from the device queue.

Parameters:

unit (str) – Time unit for timestamps (“cts”, “us”, or “ms”)

Returns:

List of Event objects representing scheduled events

Return type:

list

Example

>>> events = sd.get_events("us")
>>> for event in events:
...     print(f"{event.func} at {event.ts} {event.unit}")
get_function_addr()[source]

Get the function address mapping from the device.

Returns:

Mapping of function names to their addresses

Return type:

dict

Note

This is used internally to map function addresses to readable names.

get_property(prop)[source]

Get a device property value; if the property is write-only, it will return an error.

Parameters:

prop – Property enum or integer ID, see props.h for available properties

Returns:

Property value as string

Return type:

str

Example

>>> version = sd.get_property(props.ro_VERSION)
get_status()[source]

Get detailed system status information.

The status report includes the following information: - Firmware version - System status header - Number of events in the event queue - System timer status (RUNNING or STOPPED) - System time in seconds

Example

>>> status = sd.get_status()
>>> print(status)
go()[source]

Start the system timer and begin processing scheduled events.

This method starts the hardware timer that processes the event queue. All scheduled events will be called exactly at their specified timestamps.

If more than one event is scheduled at the same time, their order of execution is undefined.

Example

>>> sd.pos_pulse("A0", 1000, ts=1000)  # Sends positive pulse 1ms after go() is called
>>> sd.go()  # Start processing events
property interlock_enabled

Check if the laser interlock is enabled. The interlock is a safety feature that prevents the laser from being turned on if the interlock circuit is broken. By default, the interlock is active.

Returns:

True if interlock is active, False otherwise

Return type:

bool

neg_pulse(pin, duration=0, ts=0, N=0, interval=0)[source]

Generate a negative pulse on a pin. Attempting to generate a pulse on a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • duration (int) – Pulse duration (in microseconds)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.neg_pulse("A0", 1000, ts=5000, N=10, interval=50000)
open_shutters(mask=0)[source]

Open all laser shutters. Use the mask argument to specify which shutters to open. Omitting the mask argument will open all shutters.

Parameters:

mask (int) –

Bitmask specifying which shutters to open:

  • 0: Opens all shutters (note: This differs from the behavior of the mask in the selected_lasers property.)

  • 1: Cy2 only

  • 2: Cy3 only

  • 4: Cy5 only

  • 8: Cy7 only

  • Combinations: 1|2|4 = Cy2, Cy3, and Cy5

Example

>>> sd.open_shutters()  # Open all shutters
>>> sd.open_shutters(1 | 4)  # Open Cy2 and Cy5 only
pos_pulse(pin, duration=0, ts=0, N=0, interval=0)[source]

Generate a positive pulse on a pin. Attempting to generate a pulse on a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • duration (int) – Pulse duration (in microseconds)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.pos_pulse("A0", 1000, ts=5000, N=10, interval=50000)
property prescaler

Get the sync device timer prescaler value. The Arduino Due runs at 84 MHz, and the system timer is clocked at 84 MHz / prescaler. The prescaler defines the system time resolution (duration of one tick, ranging from 24 ns to 1.524 µs), as well as the maximum allowable timestamp value \(t_\mathrm{max}\) (\(2^{32}\) ticks).

\(t_\mathrm{max}\) is defined as \(2^{32} \cdot \mathrm{prescaler} / 84\) µs, and ranges from 1min 42s to 1h 49min.

Returns:

Timer prescaler (2, 8, 32, or 128)

Return type:

int

Note

The prescaler is hardcoded in the firmware, and cannot be changed at runtime.

See globals.h for the prescaler values and their corresponding system time resolution and maximum timestamp value.

property pulse_duration_us

Get the default pulse duration in microseconds. The default pulse duration is the duration of a positive or negative pulse generated by the pos_pulse() and neg_pulse() methods, and can be changed at runtime.

Returns:

Default pulse duration in microseconds

Return type:

int

pulse_train(period, duration=0, ts=0, N=0, interval=0)[source]

Generate a burst of pulses.

Parameters:
  • period (int) – Period between pulses (in microseconds)

  • duration (int) – Duration of each pulse (in microseconds)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.pulse_train(1000, 100, ts=0, N=1000)  # 1000 pulses, 1kHz
query(cmd, arg1=0, arg2=0, ts=0, N=0, interval=0)[source]

Query the sync device - write a command and read the reply.

Parameters:

cmd (str)

reset()[source]

Reset the sync device and clear all events.

This method performs a soft reset of the device, clearing all events and resetting system parameters to their default values. A “soft reset” triggers a processor reset via software by writing a key and command to the Reset Controller (RSTC), which restarts the CPU without cycling power or affecting external peripherals.

Note

This operation will immediately stop the running hardware system timer, clear the event queue, and restart the device firmware. All scheduled events and timer state will be lost, and the device will reboot to its initial state, and send a startup message, indicating the firmware version.

Example

>>> sd.reset()  # Reset device to default state
property running

Check whether the sync device system timer is running.

Returns:

True if system timer is active, False otherwise

Return type:

bool

property selected_lasers

Get the currently enabled laser channels.

Returns:

Bitmask of enabled laser channels

Return type:

int

Example

>>> mask = sd.selected_lasers
>>> print(f"Enabled lasers: {bin(mask)}")
set_pin(pin, level, ts=0, N=0, interval=0)[source]

Set a pin to a specific logical level. Attempting to set a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • level (int) – Pin level (0=low, 1=high)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.set_pin("A0", 1, ts=1000)  # Set A0 high after 1ms
set_property(prop, value)[source]

Set a device property value; if the property is read-only, it will return an error.

Parameters:
  • prop – Property enum or integer ID, see props.h for available properties

  • value – New property value

Example

>>> sd.set_property(props.rw_DFLT_PULSE_DURATION_us, 1000)
property shutter_delay_us

Get the pre-programmed laser shutter delay time.

Returns:

Shutter delay time in microseconds

Return type:

int

start_ALEX_acq(exp_time, N_bursts, ts=0, burst_period=0)[source]

Start ALEX (Alternating Laser Excitation) acquisition.

In ALEX mode, frames are acquired in bursts, with each frame in a burst illuminated by a different laser channel. This enables multi-spectral imaging, and is useful for acquiring images of multiple fluorophores with different emission wavelengths.

Parameters:
  • exp_time (int) – Exposure time in microseconds

  • N_bursts (int) – Number of bursts to acquire

  • ts (int) – Start time offset in microseconds

  • burst_period (int) – Time between bursts for timelapse (microseconds)

Example

>>> sd.start_ALEX_acq(50000, 9, burst_period=400000)
start_continuous_acq(exp_time, N_frames, ts=0)[source]

Start continuous acquisition mode.

In continuous mode, laser shutters remain open during the entire acquisition and the camera is triggered at precise intervals. The first frame is automatically discarded as it contains pre-acquisition noise.

Parameters:
  • exp_time (int) – Exposure time in microseconds

  • N_frames (int) – Number of frames to acquire

  • ts (int) – Start time offset in microseconds

Example

>>> sd.start_continuous_acq(200000, 15, ts=500000)  # Acquire 15 frames with 200ms exposure, start at t=500ms
start_stroboscopic_acq(exp_time, N_frames, ts=0, frame_period=0)[source]

Start stroboscopic or timelapse acquisition.

In stroboscopic mode, the laser shutter is briefly opened during each camera exposure, followed by a readout period. The interval between frames is set by the optional frame_period parameter, which can be used to add a delay between laser pulses for timelapse acquisition.

Parameters:
  • exp_time (int) – Exposure time in microseconds

  • N_frames (int) – Number of frames to acquire

  • ts (int) – Start time offset in microseconds

  • frame_period (int) – Time between frames for timelapse (microseconds)

Example

>>> # Acquire 10 frames every 500ms with 100ms long laser exposure (timelapse mode)
>>> sd.start_stroboscopic_acq(100000, 10, frame_period=500000)
stop()[source]

Stop the sync device system timer and halt event processing.

This method stops and resets the hardware timer, and deletes the event queue.

Example

>>> sd.stop()  # Pause event processing
>>> # schedule some events
>>> sd.go()    # Start processing events (from t=0)
property sys_time_cts

Get current sync device system time in counter ticks.

Returns:

64-bit system time in counter ticks

Return type:

int

property sys_time_s

Get current sync device system time in seconds.

Returns:

System time in seconds

Return type:

float

tgl_pin(pin, ts=0, N=0, interval=0)[source]

Toggle a pin state. Attempting to toggle a previously unused pin configures it as an output pin.

Parameters:
  • pin (str) – Arduino Due pin name (e.g., “A0”, “D13”)

  • ts (int) – Timestamp (in microseconds, relative to current time)

  • N (int) – Number of event repetitions (0=infinite)

  • interval (int) – Interval between event repetitions (in microseconds)

Example

>>> sd.tgl_pin("D13", N=1000, interval=1000)  # Toggle D13 every 1ms
property version

Get the firmware version. The version is a string of the form “X.Y.Z”, where X=major, Y=minor, and Z=patch. The major and minor version number of the firmware and the driver must match.

Returns:

Firmware version string (e.g., “2.4.0”)

Return type:

str

property watchdog_timeout_ms

Get the watchdog timeout value in milliseconds. The watchdog is a safety feature that resets the sync device if it stops responding for a certain amount of time. This can happen i.e. if too many events are scheduled, and the sync device is not managing to process them in a timely manner.

Returns:

Watchdog timeout in milliseconds, 100 ms by default

Return type:

int

write(cmd, arg1=0, arg2=0, ts=0, N=0, interval=0)[source]

Send a command to the synchronization device. If the device is in a context manager, the command is queued and transmitted as a single batch when exiting the context manager. If the device is not in a context manager, the command is transmitted immediately.

Parameters:
  • cmd (str) – 3-character command code

  • arg1 – First argument (can be string or integer)

  • arg2 (int) – Second argument

  • ts (int) – Timestamp (in microseconds)

  • N (int) – Number of event repetitions

  • interval (int) – Interval between event repetitions (in microseconds)

Note

This is a low-level method. For most applications, use the high-level methods like pos_pulse(), tgl_pin(), etc.

class props(value)[source]

Enum class for the properties of the sync device. See corresponding enum in props.h

ro_N_EVENTS = 8

Number of events in queue (read-only)

ro_SYS_TIMER_OVF_COUNT = 3

System timer overflow count (read-only)

ro_SYS_TIMER_PRESCALER = 5

System timer prescaler value (read-only)

ro_SYS_TIMER_STATUS = 1

System timer running status (read-only)

ro_SYS_TIMER_VALUE = 2

Current system timer value (read-only)

ro_SYS_TIME_s = 4

Current system time in seconds (read-only)

ro_VERSION = 0

Device version number (read-only)

ro_WATCHDOG_TIMEOUT_ms = 7

Watchdog timeout in milliseconds (read-only)

rw_CAM_READOUT_us = 14

Camera readout time in microseconds (read-write)

rw_DFLT_PULSE_DURATION_us = 6

Default pulse duration in microseconds (read-write)

rw_INTLCK_ENABLED = 9

Laser interlock enabled state (read-write)

rw_SELECTED_LASERS = 10

Selected laser mask (read-write)

rw_SHUTTER_DELAY_us = 13

Shutter delay in microseconds (read-write)

wo_CLOSE_SHUTTERS = 12

Close all shutters (write-only)

wo_OPEN_SHUTTERS = 11

Open all shutters (write-only)