Camera API reference

Contents

Camera API reference#

class pyTelops.Camera(ip: str | None = None, local_ip: str | None = None, timeout: float = 2.0)[source]#

Bases: object

Telops FAST-series thermal camera over GigE Vision.

Provides register-level control (GVCP) and frame streaming (GVSP) for Telops FAST infrared cameras. Supports live single-frame and burst acquisition, internal memory-buffer recording, hardware and software triggering, and a lightweight GUI viewer.

All resolution values are in usable pixels (the driver hides the two Telops metadata rows). In "RT" calibration mode the driver automatically converts frames to degrees Celsius using per-frame header data. In "NUC" or "RAW" mode frames are raw 16-bit integers.

Parameters:
  • ip (str or None, optional) – Camera IPv4 address (e.g. "169.254.67.34"). When None (default) the driver broadcasts a GVCP discovery and uses the first Telops camera found on the network.

  • local_ip (str or None, optional) – IPv4 address of the local network interface to use. When None (default) the driver auto-detects the interface that can reach the camera.

  • timeout (float, optional) – UDP socket timeout in seconds for GVCP operations. Default is 2.0.

Examples

Auto-discover and grab a single frame:

>>> with Camera() as cam:
...     frame = cam.grab()

Connect to a specific camera and acquire a burst:

>>> cam = Camera(ip="169.254.67.34")
>>> cam.connect()
>>> cam.integration_time = 100.0
>>> frames = cam.acquire(50)
>>> cam.disconnect()

Internal memory-buffer recording:

>>> with Camera() as cam:
...     cam.buffer_configure(frames_per_seq=1000)
...     cam.buffer_arm()
...     cam.buffer_fire_moi()
...     data = cam.buffer_download()
HEADER_ROWS = 2#
WIDTH_MIN = 64#
WIDTH_MAX = 320#
WIDTH_STEP = 64#
HEIGHT_MIN = 4#
HEIGHT_MAX = 256#
HEIGHT_STEP = 4#
connect() None[source]#

Discover the camera (if needed) and establish GVCP control.

If no IP was supplied at construction time, a GVCP broadcast is sent and the first Telops camera found is used. If another Camera instance in the same process is still connected to the same camera IP it is disconnected first, which handles the common “forgot to disconnect” and “kernel restart” scenarios. A stale CCP grant held by a process that has already exited is reclaimed automatically when the camera’s heartbeat timeout expires (typically within 15 s).

After the GVCP handshake the driver applies a set of sensible defaults (bad-pixel replacement on, fixed frame-rate mode, test image off) and, if the camera reports REG_DEVICE_NOT_READY, blocks in wait_until_ready() until it is ready. Idempotent when already connected.

Raises:
  • RuntimeError – If no Telops camera is found on the network.

  • GVCPError – If the GVCP handshake fails or a register write is rejected.

Examples

>>> cam = Camera()
>>> cam.connect()
>>> cam.is_connected
True
>>> cam.disconnect()
wait_until_ready(timeout: float = 120.0, verbose: bool = True) None[source]#

Block until the camera finishes cooling down and initialising.

Polls REG_DEVICE_NOT_READY every two seconds. If verbose is True, the current TDC status bits (e.g. “Cooling down (18.5 C)”) are printed on a single overwriting line so the terminal is not flooded. Called automatically by connect(), grab(), acquire(), and buffer_record() when the camera is not yet ready.

Parameters:
  • timeout (float, optional) – Maximum seconds to wait before raising. Default 120.0.

  • verbose (bool, optional) – Print a live status line while waiting. Default True.

Raises:
  • TimeoutError – If the camera is still not ready after timeout seconds.

  • RuntimeError – If the camera is not connected.

property tdc_status: int#

Raw TDC status bitmask from REG_TDC_STATUS.

Each bit corresponds to a TDC_* constant in pyTelops.registers. Useful for diagnosing why the camera is not ready without waiting for the full wait_until_ready() timeout.

Returns:

Bitmask of active TDC status flags.

Return type:

int

Raises:

RuntimeError – If the camera is not connected.

disconnect() None[source]#

Stop streaming, release GVCP control, and close all sockets.

Calls stop_stream() if streaming is active, closes the GVSP receiver, and releases the GVCP CCP grant. Idempotent when already disconnected. Called automatically by __exit__() and __del__().

property is_connected: bool#

Whether the camera is connected.

Returns:

True after a successful connect(); False after disconnect() or before the first connection.

Return type:

bool

property is_streaming: bool#

Whether GVSP streaming is active.

Returns:

True between start_stream() and stop_stream().

Return type:

bool

property is_acquiring: bool#

Whether continuous frame acquisition is active.

Returns:

True between acquisition_start() and acquisition_stop(), or while inside an acquisition() context manager.

Return type:

bool

property camera_ip: str | None#

Camera IPv4 address, or None if not yet discovered.

Returns:

The address used (or to be used) for the GVCP connection. Set during connect() when auto-discovery is used.

Return type:

str or None

property valid_widths: list[int]#

All valid frame widths in pixels.

Widths are multiples of WIDTH_STEP (64) in the range [WIDTH_MIN, WIDTH_MAX] i.e. [64, 128, 192, 256, 320].

Returns:

Sorted list of valid width values.

Return type:

list of int

property valid_heights: list[int]#

All valid frame heights in usable pixels.

Heights are multiples of HEIGHT_STEP (4) in the range [HEIGHT_MIN, HEIGHT_MAX] i.e. [4, 8, ..., 252, 256]. The two Telops header rows are not counted here; the driver adds them back before writing the hardware register.

Returns:

Sorted list of valid height values.

Return type:

list of int

property integration_time: float#

Integration (exposure) time in microseconds.

The camera-native term is exposure time; integration_time is the thermal-imaging convention. The two are interchangeable and exposure is kept as a backward-compatible alias.

Returns:

Current integration time in microseconds.

Return type:

float

Raises:

RuntimeError – If the camera is not connected.

Examples

>>> with Camera() as cam:
...     cam.integration_time = 50.0
...     cam.integration_time
50.0
property exposure: float#

Alias for integration_time (backward-compatible).

property integration_time_auto: ExposureAuto#

Automatic exposure control (AEC) mode.

When not "off", the camera adjusts integration time automatically. Setting integration_time while AEC is active will first disable AEC.

Returns:

Current AEC mode enum value.

Return type:

reg.ExposureAuto

Raises:

RuntimeError – If the camera is not connected.

property exposure_auto: ExposureAuto#

Alias for integration_time_auto (backward-compatible).

property frame_rate_max: float#

Maximum achievable frame rate for the current settings (Hz).

Depends on resolution and integration time. Use this to determine the upper bound before setting frame_rate.

Returns:

Maximum frame rate in Hz.

Return type:

float

Raises:

RuntimeError – If the camera is not connected.

property frame_rate: float#

Acquisition frame rate in Hz.

The camera clamps this to frame_rate_max whenever resolution or integration time changes. The setter emits a UserWarning if the requested value exceeds the maximum for the current settings.

Returns:

Current frame rate in Hz.

Return type:

float

Raises:

RuntimeError – If the camera is not connected.

Examples

>>> with Camera() as cam:
...     cam.frame_rate = 100.0
...     cam.frame_rate
100.0
property calibration_mode: CalibrationMode#

Active calibration pipeline mode.

Determines what processing the camera applies to raw sensor data before transmitting frames over GVSP. In "RT" mode the driver automatically converts pixel values to degrees Celsius using the per-frame header coefficients.

Returns:

Current calibration mode enum value.

Return type:

reg.CalibrationMode

Raises:

RuntimeError – If the camera is not connected.

property resolution: tuple[int, int]#

Frame resolution as (width, height) in usable pixels.

Width must be a multiple of 64 in the range [64, 320]. Height must be a multiple of 4 in the range [4, 256]. The two Telops header rows are excluded from the height value here; the driver adds them back automatically when writing the hardware register. Use valid_widths and valid_heights to enumerate all accepted values.

Returns:

(width, height) in usable pixels.

Return type:

tuple of (int, int)

Raises:

RuntimeError – If the camera is not connected.

Examples

>>> with Camera() as cam:
...     cam.resolution = (320, 256)
...     cam.resolution
(320, 256)
property temperature: float#

Main camera sensor temperature in degrees Celsius (read-only).

Reports the value from REG_DEVICE_TEMPERATURE. For other internal temperature sensors (compressor, FPGAs, etc.) use sensor_temperature().

Returns:

Sensor temperature in degrees Celsius.

Return type:

float

Raises:

RuntimeError – If the camera is not connected.

property info: dict#

Current camera configuration as a dictionary.

Reads a snapshot of the most commonly needed settings in one call. Useful for logging state before a recording session.

Returns:

Keys: ip, width, height, integration_time_us, integration_time_auto, frame_rate_hz, frame_rate_max_hz, calibration, trigger_mode, power_state, temperature_c, buffer_mode, bad_pixel_replacement, reverse_x, reverse_y, test_image, frame_rate_mode, roi_offset.

Return type:

dict

Raises:

RuntimeError – If the camera is not connected.

Examples

>>> with Camera() as cam:
...     cfg = cam.info
...     print(cfg["calibration"])
RT
property state: str#

High-level camera state as a string.

Possible values: "disconnected", "connected", "streaming", "standby", "not_ready", "error".

Returns:

Current camera state.

Return type:

str

property bad_pixel_replacement: bool#

Bad-pixel auto-replacement (enabled by default).

When enabled the camera replaces pixels flagged as defective with the average of their neighbours before transmitting. Enabled automatically by connect(). Disable only for diagnostics.

Returns:

True if bad-pixel replacement is active.

Return type:

bool

Raises:

RuntimeError – If the camera is not connected.

property reverse_x: bool#

Horizontal image flip (mirror left-right).

Returns:

True if horizontal flipping is active.

Return type:

bool

Raises:

RuntimeError – If the camera is not connected.

property reverse_y: bool#

Vertical image flip (mirror top-bottom).

Returns:

True if vertical flipping is active.

Return type:

bool

Raises:

RuntimeError – If the camera is not connected.

property test_image: TestImageSelector#

Internal test-pattern source.

Use "off" (the default set by connect()) for normal operation. Test patterns are useful for verifying streaming without a physical scene.

Returns:

Current test image selector enum value.

Return type:

reg.TestImageSelector

Raises:

RuntimeError – If the camera is not connected.

property roi_offset: tuple[int, int]#

Region-of-interest pixel offset as (x, y).

Defines the top-left corner of the active area on the sensor. x must be a non-negative multiple of WIDTH_STEP (64); y must be a non-negative multiple of HEIGHT_STEP (4). The combination of offset and resolution must not exceed the full sensor size (320 x 256).

Returns:

(x, y) pixel offset from the top-left of the sensor.

Return type:

tuple of (int, int)

Raises:

RuntimeError – If the camera is not connected.

property frame_rate_mode: FrameRateMode#

Frame-rate control mode.

Controls how the camera determines its output frame rate.

  • "fixed" – use the value in frame_rate (default set by connect()).

  • "fixed_locked" – locked to an external timing source.

  • "maximum" – always run at frame_rate_max.

  • "burst" – burst mode (used with trigger frame count).

Returns:

Current frame-rate mode enum value.

Return type:

reg.FrameRateMode

Raises:

RuntimeError – If the camera is not connected.

property trigger_frame_count: int#

Number of frames captured per trigger event.

Relevant when frame_rate_mode is "burst" or when using trigger_software(). The camera emits this many frames after each trigger pulse.

Returns:

Current trigger frame count.

Return type:

int

Raises:

RuntimeError – If the camera is not connected.

property packet_delay: int#

Inter-packet delay for GVSP streaming in camera timer ticks.

Each tick is 8 ns on Telops cameras. The camera inserts this much delay between successive packets within one frame burst, which spreads the data over time and reduces host-side UDP receive overflow at the cost of slightly lower maximum frame rate.

Typical values:

  • 0 – no delay (default). Maximum throughput. Works on clean networks with a fast receiver. Risk of packet loss if the host has scheduling jitter (GC, display redraws).

  • 1000 – ~8 us between packets. Spreads a 113-packet frame over ~2 ms. Usable up to ~400 fps. Safe default for live processing loops with non-trivial host work.

  • 5000 – ~40 us between packets. Very conservative, max ~100 fps. Use only if 1000 is not enough.

Writing this property sends the new value to the camera register immediately and caches it so it is re-applied on subsequent start_stream() calls, surviving stream restarts and context-manager re-entry.

This setting has no effect on internal memory-buffer recording, which runs at sensor speed inside the camera. It does, however, pace the buffer download stream (the same stream channel): a small delay (around 1000 ticks) can clear host-side packet drops during download while keeping more throughput than lowering the download bitrate.

Returns:

Current inter-packet delay in camera timer ticks.

Return type:

int

Raises:

RuntimeError – If the camera is not connected.

start_stream() None[source]#

Configure the GVSP stream channel and start the receiver thread.

Sets the packet size to the standard MTU (1500 bytes), writes the destination IP and port to the camera, and starts the GVSP receiver. Idempotent – safe to call when streaming is already active.

After this call, frames flow from the camera but are not queued in the acquisition buffer until acquisition_start() is also called. For a single combined start, use acquisition_start() directly (it calls start_stream() automatically).

Raises:

RuntimeError – If the camera is not connected.

stop_stream() None[source]#

Stop the GVSP receiver and tear down the stream channel.

If acquisition is currently running, acquisition_stop() is called first. Then the camera’s host-port register is cleared and the GVSP receiver thread is stopped. Idempotent – safe to call when streaming is already inactive.

To pause acquisition without releasing the socket (so the next acquisition_start() is faster), use acquisition_stop() alone instead of this method.

acquisition_start() None[source]#

Start continuous frame acquisition.

Calls start_stream() if the GVSP channel is not yet open, then writes the acquisition-start register. Frames begin flowing and can be retrieved with read_frame(). Idempotent – safe to call when already acquiring.

Pair with acquisition_stop() to halt. For automatic cleanup on exception, prefer the acquisition() context manager:

with cam.acquisition():
    while running:
        frame = cam.read_frame(timeout=0.1)
        if frame is not None:
            process(frame)
Raises:

RuntimeError – If the camera is not connected or not ready.

Notes

Not thread-safe. Acquisition lifecycle calls (acquisition_start / acquisition_stop) must be serialized by the caller. read_frame() is safe to call concurrently with itself from multiple threads.

acquisition_stop() None[source]#

Stop continuous frame acquisition.

Writes the acquisition-stop register and clears the internal _acquiring flag. The GVSP stream channel is left intact so a subsequent acquisition_start() can resume without re-binding sockets. For a full teardown (including the receiver thread), call stop_stream(). Idempotent – safe to call when not acquiring.

Notes

Not thread-safe. Acquisition lifecycle calls (acquisition_start / acquisition_stop) must be serialized by the caller. read_frame() is safe to call concurrently from multiple threads.

acquisition() Iterator[Camera][source]#

Context manager for continuous frame acquisition.

Calls acquisition_start() on entry and acquisition_stop() on exit, even if an exception is raised inside the block. The GVSP stream channel is left open after exit so a subsequent acquisition_start() (or with cam.acquisition()) can resume without re-binding sockets.

Yields:

Camera – The camera instance itself, for fluent use inside the block.

Raises:

RuntimeError – If the camera is not connected or not ready (propagated from acquisition_start()).

Examples

>>> with cam.acquisition() as c:
...     for _ in range(100):
...         frame = c.read_frame(timeout=0.1)
...         if frame is not None:
...             process(frame)
read_frame(timeout: float = 0.0, strip_header: bool = True, convert: bool = True, latest: bool = False) ndarray | None[source]#

Pop one frame from the acquisition queue.

Must be called after acquisition_start() or inside an acquisition() block. Non-blocking by default.

Parameters:
  • timeout (float, optional) – Seconds to wait for a frame. 0.0 (default) returns immediately with whatever is queued, or None if empty. Use a small positive value (e.g. 0.1) to block briefly.

  • strip_header (bool, optional) – Remove the two Telops metadata rows. Default True. When convert=True the headers are consumed by the calibration step regardless of this flag.

  • convert (bool, optional) – Convert pixel values to physical units using the per-frame header coefficients. In RT mode this yields float32 degrees Celsius; in other modes the conversion is still applied but the result is in the camera’s native units. Set False to get raw uint16 counts. Default True.

  • latest (bool, optional) – When True, drain the queue and return only the newest frame, discarding stale ones. Use for live displays where lag must not accumulate. When False (default), return frames in order – the correct choice for measurement and logging.

Returns:

2-D array of shape (H, W). dtype is float32 when convert=True (RT mode), uint16 otherwise. Returns None if no frame was available within timeout.

Return type:

numpy.ndarray or None

Raises:

RuntimeError – If acquisition is not currently running.

Notes

Thread-safe – multiple threads may call read_frame() concurrently. The underlying GVSP frame queue handles inter-thread coordination.

Examples

Non-blocking poll inside a loop:

>>> cam.acquisition_start()
>>> frame = cam.read_frame(timeout=2.0)
>>> cam.acquisition_stop()

Live-display loop with stale-frame draining:

>>> with cam.acquisition():
...     while displaying:
...         frame = cam.read_frame(timeout=0.05, latest=True)
...         if frame is not None:
...             show(frame)
grab(timeout: float = 5.0, strip_header: bool = True, convert: bool = True) ndarray | None[source]#

Grab a single frame.

Convenience wrapper for one-shot acquisition. If streaming or acquisition are not already active they are started and then restored to their prior state after the frame is captured. For repeated access in a loop, prefer acquisition() + read_frame() – this method carries per-call setup overhead.

Parameters:
  • timeout (float, optional) – Seconds to wait for a frame. Default 5.0.

  • strip_header (bool, optional) – Remove the two Telops metadata rows. Default True. Ignored when convert=True because the calibration step handles header removal.

  • convert (bool, optional) – Apply per-frame calibration. In RT mode this yields float32 degrees Celsius. Set False for raw uint16 counts. Default True.

Returns:

2-D array of shape (H, W). dtype is float32 when convert=True (RT mode), uint16 otherwise. Returns None on timeout.

Return type:

numpy.ndarray or None

Raises:

RuntimeError – If the camera is not connected or not ready.

Examples

>>> with Camera() as cam:
...     frame = cam.grab()  # float32 Celsius, RT mode
...     raw = cam.grab(convert=False)  # uint16 raw counts
acquire(n_frames: int, timeout: float = 30.0, strip_header: bool = True, convert: bool = True) ndarray | None[source]#

Acquire a burst of frames via live streaming.

Starts streaming and acquisition if not already active, collects exactly n_frames frames (or as many as arrive before timeout expires), then restores the prior state.

Parameters:
  • n_frames (int) – Number of frames to capture.

  • timeout (float, optional) – Total wall-clock timeout in seconds across all frames. Default 30.0.

  • strip_header (bool, optional) – Remove the two Telops metadata rows. Default True. Ignored when convert=True because the calibration step handles header removal.

  • convert (bool, optional) – Apply per-frame calibration. In RT mode this yields float32 degrees Celsius. Set False for raw uint16 counts. Default True.

Returns:

3-D array of shape (N, H, W) where N is the number of frames actually received (may be less than n_frames on timeout). dtype is float32 when convert=True (RT mode), uint16 otherwise. Returns None if no frames were captured.

Return type:

numpy.ndarray or None

Raises:

RuntimeError – If the camera is not connected or not ready.

configure_trigger(source: TriggerSource | str | int = 'external', activation: TriggerActivation | str | int = 'rising', selector: TriggerSelector | str | int = 'acquisition_start', enabled: bool = True) None[source]#

Configure the hardware or software trigger.

Writes the trigger selector, source, activation, and mode registers in a single call. After this, the camera waits for a trigger before each frame (or acquisition start, depending on selector).

Parameters:
  • source (reg.TriggerSource, str, or int, optional) – Trigger source. Accepted strings (case-insensitive): "external" – BNC connector (default), "software"software_trigger(). Also accepts the reg.TriggerSource enum directly or its integer value.

  • activation (reg.TriggerActivation, str, or int, optional) – Edge or level that fires the trigger. Accepted strings: "rising" (default), "falling", "any". Also accepts reg.TriggerActivation directly or its integer value. "level_high" and "level_low" are available as enum members but have no alias string – pass the enum or integer.

  • selector (reg.TriggerSelector, str, or int, optional) – Which camera event the trigger controls. Accepted strings: "acquisition_start" (default), "flagging", "gating". Also accepts reg.TriggerSelector directly or its integer value.

  • enabled (bool, optional) – True (default) to enable trigger mode; False to disable it (free-running).

Raises:
  • RuntimeError – If the camera is not connected.

  • ValueError – If source, activation, or selector is an unrecognised string.

software_trigger() None[source]#

Send a software trigger pulse to the camera.

Writes 1 to REG_TRIGGER_SOFTWARE. Has effect only when trigger mode is enabled and the source is set to "software" (see configure_trigger()).

Raises:

RuntimeError – If the camera is not connected.

nuc(mode: str | ImageCorrectionMode = 'black_body', blackbody_temp: float | None = None, timeout: float = 60.0) None[source]#

Perform Non-Uniformity Correction (NUC).

Writes the correction mode and (optionally) the external blackbody temperature, then triggers the NUC sequence and polls REG_DEVICE_NOT_READY once per second until the camera reports ready. Many registers are locked by the camera during this time.

Parameters:
  • mode (str or reg.ImageCorrectionMode, optional) – Correction algorithm. Accepted strings (case-insensitive): "black_body" (default) or "icu". Also accepts the reg.ImageCorrectionMode enum directly.

  • blackbody_temp (float or None, optional) – External blackbody reference temperature in degrees Celsius. Used only in "black_body" mode. When None (default) the register is not written and the camera uses whatever value was previously programmed.

  • timeout (float, optional) – Maximum seconds to wait for the NUC to finish. Default 60.0.

Raises:
  • RuntimeError – If the camera is not connected.

  • TimeoutError – If the NUC sequence does not complete within timeout seconds.

sensor_temperature(location: str | TemperatureLocation = 'sensor') float[source]#

Read the temperature at a specific camera location.

Writes the selector register then reads the float result register. For a snapshot of all locations at once, use diagnostics().

Parameters:

location (str or reg.TemperatureLocation, optional) – Sensor location identifier. Accepted strings (case-insensitive): "sensor", "mainboard", "internal_lens", "external_lens", "icu", "filter_wheel", "compressor", "cold_finger", "spare", "external_thermistor", "processing_fpga", "output_fpga", "storage_fpga". Defaults to "sensor". Also accepts the reg.TemperatureLocation enum or its integer value.

Returns:

Temperature in degrees Celsius.

Return type:

float

Raises:
diagnostics() dict[source]#

Read all diagnostic sensors in one call.

Iterates over every entry in reg.TemperatureLocation, reg.VoltageLocation, and reg.CurrentLocation, writing each selector register and reading the corresponding float register. Sensors that the camera rejects with a GVCPError (unsupported on this model) are stored as None. The call issues roughly 40 register reads and typically completes within a few hundred milliseconds.

Returns:

A dict with the following keys:

"temperatures" (dict[str, float or None])

Keyed by lowercase reg.TemperatureLocation member names (e.g. "sensor", "compressor", "cold_finger", "processing_fpga"). Values in degrees Celsius; None if the location is not supported by this camera model.

"voltages" (dict[str, float or None])

Keyed by lowercase reg.VoltageLocation member names (e.g. "cooler", "supply_24v"). Values in volts; None if unsupported.

"currents" (dict[str, float or None])

Keyed by lowercase reg.CurrentLocation member names (e.g. "cooler", "supply_24v"). Values in amps; None if unsupported.

"device_running_s" (int)

Total device uptime in seconds.

"cooler_running_s" (int)

Total cooler uptime in seconds.

"power_on_cycles" (int)

Number of times the device has been powered on.

"cooler_power_on_cycles" (int)

Number of times the cooler has been powered on.

Return type:

dict

Raises:

RuntimeError – If the camera is not connected.

Examples

>>> d = cam.diagnostics()
>>> print(d["temperatures"]["sensor"])
-196.3
>>> print(d["voltages"]["cooler"])
4.85
>>> print(d["device_running_s"] / 3600, "hours")
12.4 hours
save_config() None[source]#

Save the current configuration to camera non-volatile memory.

Writes 1 to REG_SAVE_CONFIGURATION. The camera persists all writable registers (integration time, resolution, frame rate, trigger settings, etc.) so they are restored on next power-on.

Raises:

RuntimeError – If the camera is not connected.

sync_time() None[source]#

Synchronise the camera clock to the host system time (UTC).

Reads the current UTC time from the host and writes the integer POSIX timestamp to REG_POSIX_TIME. Sub-second precision is not written; use the posix_time setter with a datetime.datetime object for finer control.

Raises:

RuntimeError – If the camera is not connected.

property posix_time: datetime#

Camera wall-clock time as a timezone-aware UTC datetime.

Reads REG_POSIX_TIME (whole seconds) and REG_SUB_SECOND_TIME (100-nanosecond ticks) from the camera and combines them into a datetime.datetime with microsecond resolution.

Returns:

Timezone-aware datetime in UTC with microsecond precision.

Return type:

datetime.datetime

Raises:

RuntimeError – If the camera is not connected.

property gev_timestamp_ns: int#

GigE Vision free-running timestamp in nanoseconds (read-only).

Latches the camera’s GigE Vision internal counter by writing 2 to REG_GEV_TIMESTAMP_CONTROL, then reads the 64-bit tick value from the high and low word registers and the tick frequency. The tick count is scaled to nanoseconds as ticks * 1_000_000_000 / freq. If the camera reports a frequency of zero the raw tick count is returned unchanged.

This timestamp is independent of wall-clock time; use posix_time or sync_time() for UTC-anchored time.

Returns:

Elapsed time since the camera was powered on, in nanoseconds.

Return type:

int

Raises:

RuntimeError – If the camera is not connected.

property calibration_names: dict[int, str]#

Manual name mapping {collection_index: name} for calibration collections.

Provides human-readable labels that appear in the output of calibration_collections(), calibration_load(), and calibration_active() without requiring the USB calibration data directory. A connection to the camera is not needed to set this mapping.

Returns:

Current {index: name} mapping (empty by default).

Return type:

dict[int, str]

See also

load_calibration_info

Load lens/temperature metadata from the calibration data directory on USB.

load_calibration_info(path: str) None[source]#

Load calibration metadata from the USB calibration data directory.

Parses .tsco filenames and exposure-time text files to build a mapping from camera collection indices to lens names, filter-wheel positions, and calibrated temperature ranges. A camera connection is not required – the method reads only local files. When connected, indices are resolved immediately; when called before connect(), the raw file data is stored and matched on connection.

After this call, calibration_collections() will include "lens", "fw_position", and "temp_range" fields where available, and calibration_load() supports the lens= / temp= selection path.

Directory layout expected#

<path>/

One or more .tsco files whose names encode the sensor serial number, EL identifier, filter-wheel position (FW), and a POSIX timestamp. Two filename formats are supported:

  • Old: TEL08050_<POSIX>_ELxxxxx_MFxxxxx_FWn_IMn_SWDn.tsco

  • New: TEL08050_ELxxxxx_MFxxxxx_FWn_IMn_SWDn_<POSIX>.tsco

<path>/estimated_ExposureTimes/

Optional sub-directory of .txt files. Each file contains a header line with the lens name (lens "MW 50mm") and the filter-wheel position (filter wheel position #N), followed by semicolon-delimited temperature/exposure rows. The first column of the first and last data rows gives temp_min and temp_max for the collection.

Naming normalisation#

Exposure-time filenames may use ELSN as the element prefix (e.g. ELSN08887) whereas .tsco files use EL08887. This method strips the SN suffix (ELSN -> EL) before matching. Filter-wheel positions in exposure-time files are 1-indexed (FW1FW4) while .tsco files are 0-indexed (FW0FW3); the method subtracts 1 from the exposure-time value before comparing.

param path:

Absolute or relative path to the calibration data directory (e.g. "TEL-8050 Calibration Data/").

type path:

str

raises FileNotFoundError:

If path does not exist or is not a directory.

Examples

Load info before connecting (stored and matched on connection):

>>> cam.load_calibration_info("/media/usb/TEL-8050 Calibration Data")
>>> cam.connect("192.168.100.10")
>>> cam.calibration_load(lens="50mm", temp=25)

Load info after connecting (indices resolved immediately):

>>> cam.connect("192.168.100.10")
>>> cam.load_calibration_info("/media/usb/TEL-8050 Calibration Data")
>>> cols = cam.calibration_collections()
>>> for c in cols:
...     print(c["index"], c.get("lens"), c.get("temp_range"))
calibration_collections() list[dict][source]#

List all calibration collections stored on the camera.

Reads the collection count from REG_CAL_COLLECTION_COUNT, then iterates over each index reading its POSIX timestamp, type, and block count. Optional fields are included only when the corresponding data is available.

Returns:

One dict per collection. Always-present keys:

"index" (int)

0-based collection index.

"timestamp" (datetime.datetime)

Collection creation time (UTC, timezone-aware).

"posix" (int)

Raw POSIX timestamp of the collection.

"type" (str or int)

Calibration type name from reg.CalibrationCollectionType (e.g. "TELOPS_FIXED"), or the raw integer if unknown.

"blocks" (int)

Number of calibration blocks in this collection.

Optional keys (present when load_calibration_info() was called and matched this collection):

"lens" (str)

Human-readable lens name (e.g. "MW 50mm").

"fw_position" (int)

0-based filter-wheel position.

"temp_range" (tuple[float, float])

(temp_min, temp_max) in degrees Celsius.

Optional key (present when calibration_names includes this index):

"name" (str)

Manually assigned human-readable name.

Return type:

list of dict

Raises:

RuntimeError – If the camera is not connected.

calibration_load(index: int | None = None, lens: str | None = None, temp: float | None = None) dict[source]#

Load a calibration collection and activate its first block.

Exactly one of index or lens must be supplied. When lens is given, load_calibration_info() must have been called first so that lens/temperature metadata is available.

The method writes REG_CAL_COLLECTION_SELECTOR to select the target collection, then compares its POSIX timestamp to the currently active POSIX timestamp. If they match the collection is already loaded and no further register writes are performed. Otherwise it writes REG_CAL_COLLECTION_LOAD, waits 2 s, then loads block 0 via REG_CAL_BLOCK_LOAD and waits another 2 s. A UserWarning is emitted if the active POSIX register does not match the expected value after loading (the camera may still be processing).

Parameters:
  • index (int or None, optional) – 0-based collection index. Use when you know the exact index.

  • lens (str or None, optional) – Lens name substring to search (case-insensitive, e.g. "50mm", "microscope"). When multiple collections match the lens name, the one whose temp_range contains temp is preferred; ties are broken by selecting the narrowest temperature range.

  • temp (float or None, optional) – Target scene temperature in degrees Celsius. Used together with lens to select the collection whose calibrated temperature range covers this value. Ignored when index is specified.

Returns:

Information about the loaded collection. Always-present keys:

"index" (int)

Collection index that was loaded.

"posix" (int)

POSIX timestamp of the loaded collection.

Optional keys (present when metadata was available from load_calibration_info() or calibration_names):

"lens" : str, "fw_position" : int, "temp_range" : tuple[float, float], "name" : str.

Return type:

dict

Raises:
  • RuntimeError – If the camera is not connected.

  • ValueError – If neither index nor lens is provided, or if no collection matches the lens / temp criteria.

Examples

Load by explicit index:

>>> cam.calibration_load(index=4)

Load by lens and target temperature (requires prior load_calibration_info() call):

>>> cam.load_calibration_info("/media/usb/TEL-8050 Calibration Data")
>>> cam.calibration_load(lens="50mm", temp=25)
>>> cam.calibration_load(lens="microscope", temp=300)
calibration_active() dict[source]#

Return information about the currently active calibration.

Reads the active calibration type, collection POSIX timestamp, and block POSIX timestamp from camera registers. If calibration metadata was loaded via load_calibration_info(), the result is enriched with lens, filter-wheel position, and temperature range. If calibration_names contains an entry for the active collection index, its name is included as well.

Returns:

Always-present keys:

"type" (str or int)

Calibration type name from reg.CalibrationCollectionType (e.g. "TELOPS_FIXED"), or the raw integer if unknown.

"collection_posix" (int)

POSIX timestamp of the active collection (0 if none).

"collection_timestamp" (datetime.datetime or None)

UTC datetime for the active collection, or None when the POSIX value is zero.

"block_posix" (int)

POSIX timestamp of the active block (0 if none).

"block_timestamp" (datetime.datetime or None)

UTC datetime for the active block, or None when the POSIX value is zero.

Optional keys (present when metadata is available):

"index" (int)

Matched collection index.

"lens" (str)

Lens name from load_calibration_info().

"fw_position" (int)

0-based filter-wheel position.

"temp_range" (tuple[float, float])

(temp_min, temp_max) in degrees Celsius.

"name" (str)

Manually assigned name from calibration_names.

Return type:

dict

Raises:

RuntimeError – If the camera is not connected.

buffer_configure(n_sequences: int = 1, duration: float | None = None, frames_per_seq: int | None = None, pre_moi: int = 0, moi_source: str | MemoryBufferMOISource = 'software') None[source]#

Configure the internal memory buffer for recording.

The camera has a 16 GB ring buffer that records at full sensor speed (up to 3100 fps at full frame), independent of the Ethernet link. The buffer is partitioned into fixed-size sequence slots; each slot holds exactly frames_per_seq frames. The MOI (Moment of Interest) trigger marks the transition from pre-trigger to post-trigger frames within each slot.

Specify either duration (seconds; the current frame rate is used to calculate the frame count) or frames_per_seq (exact frame count). If neither is given, 100 frames per sequence is used.

If the buffer is already active or in an incompatible state, the method automatically stops acquisition, clears the buffer, and re-enables buffer mode before writing the new parameters.

Parameters:
  • n_sequences (int, optional) – Number of sequence slots to allocate in the buffer. Default 1.

  • duration (float or None, optional) – Recording duration per sequence in seconds. The frame count is derived from the current frame_rate. Mutually exclusive with frames_per_seq.

  • frames_per_seq (int or None, optional) – Exact number of frames per sequence slot. Mutually exclusive with duration. Defaults to 100 when neither argument is given.

  • pre_moi (int, optional) – Number of frames to preserve before the MOI trigger event. These frames are the “pre-trigger” portion of each slot. Default 0 (all frames are post-MOI).

  • moi_source (str or reg.MemoryBufferMOISource, optional) – Source of the MOI trigger. Accepted strings (case-insensitive): "software" – fire via buffer_fire_moi() (default), "external" – hardware signal on the BNC connector, "acquisition_started" – MOI fires automatically when acquisition begins, "none" – no MOI (record-until-full). Also accepts the reg.MemoryBufferMOISource enum or its integer value.

Raises:
  • RuntimeError – If the camera is not connected.

  • ValueError – If both duration and frames_per_seq are specified, or if duration results in zero frames at the current frame rate.

Examples

Record 200 frames split into two sequences with a software MOI:

>>> cam.buffer_configure(n_sequences=2, frames_per_seq=100)

Record 0.5 s at current frame rate with 50 pre-trigger frames:

>>> cam.buffer_configure(duration=0.5, pre_moi=50)

Configure for external hardware trigger:

>>> cam.buffer_configure(frames_per_seq=500, moi_source="external")
buffer_record(verbose: bool = True) int[source]#

Record all configured sequences to the internal buffer.

Arms the camera on the first sequence and fires a software MOI for each sequence in turn. After firing the MOI, the method polls REG_MEMORY_BUFFER_SEQ_COUNT (0xE914) to detect per-sequence completion rather than waiting for the overall buffer status to leave RECORDING. Acquisition is stopped after the final sequence.

The per-sequence timeout is derived automatically from the configured frame count and current frame rate (at least 30 s overhead, minimum 45 s total).

For external-trigger workflows where the MOI comes from a hardware signal, use the manual flow instead:

cam.buffer_configure(n_sequences=3, moi_source="external")
cam.buffer_arm()
# ... external trigger fires 3 times ...
cam.buffer_wait()       # waits for HOLDING/IDLE
Parameters:

verbose (bool, optional) – Print per-sequence progress messages to stdout. Default True.

Returns:

Total number of frames recorded across all sequences, read from the camera registers after acquisition stops.

Return type:

int

Raises:
  • RuntimeError – If the camera is not connected or not ready.

  • TimeoutError – If a sequence does not complete within the computed safety timeout.

Examples

Record a single sequence:

>>> cam.buffer_configure(n_sequences=1, frames_per_seq=100)
>>> n = cam.buffer_record()
>>> print(n)  # 100

Record three sequences back-to-back:

>>> cam.buffer_configure(n_sequences=3, frames_per_seq=50)
>>> n = cam.buffer_record()
>>> print(n)  # 150
buffer_arm() None[source]#

Arm the camera and start acquisition for buffer recording.

Writes REG_ACQUISITION_ARM then REG_ACQUISITION_START. Use this as the first step of the manual external-trigger workflow:

cam.buffer_configure(n_sequences=1, moi_source="external")
cam.buffer_arm()
# ... external MOI signal fires ...
cam.buffer_wait()

To fire the MOI in software instead, call buffer_fire_moi() after arming. For fully automated software-MOI recordings, prefer buffer_record().

Raises:

RuntimeError – If the camera is not connected.

buffer_fire_moi() None[source]#

Fire a software MOI (Moment of Interest) trigger.

Writes 1 to REG_MEMORY_BUFFER_MOI_SOFTWARE. Only has effect when buffer_arm() has been called and moi_source was set to "software" in buffer_configure().

Raises:

RuntimeError – If the camera is not connected.

buffer_wait(timeout: float = 30.0, poll_interval: float = 0.5) MemoryBufferStatus[source]#

Wait for buffer recording to complete.

Polls buffer_status() at poll_interval second intervals until the status is HOLDING or IDLE, indicating that all configured sequences have finished recording.

Parameters:
  • timeout (float, optional) – Maximum number of seconds to wait. Default 30.0.

  • poll_interval (float, optional) – Seconds between consecutive status reads. Default 0.5.

Returns:

The final buffer status (HOLDING or IDLE) when recording completes.

Return type:

reg.MemoryBufferStatus

Raises:
  • RuntimeError – If the camera is not connected.

  • TimeoutError – If the buffer does not reach HOLDING or IDLE within timeout seconds.

buffer_info() dict[source]#

Return a summary of buffer state and recorded sequences.

Reads the buffer status register, iterates over configured sequence slots to collect per-sequence frame counts, and reads the 64-bit total/free space registers (split across two 32-bit hi/lo registers).

Returns:

A dict with the following keys:

"status" (str)

Name of the current reg.MemoryBufferStatus value (e.g. "IDLE", "HOLDING", "RECORDING").

"n_sequences" (int)

Number of sequence slots configured via buffer_configure().

"recorded" (list[int])

Frame count for each sequence slot (0-based index). Entries may be 0 if a slot has not been used or if the camera returns a GVCPError for that slot.

"total_bytes" (int)

Total capacity of the onboard buffer in bytes.

"free_bytes" (int)

Remaining free space in the buffer in bytes.

Return type:

dict

Raises:

RuntimeError – If the camera is not connected.

buffer_status() MemoryBufferStatus[source]#

Read the current memory buffer status.

Writes the REFRESH sentinel to REG_MEMORY_BUFFER_STATUS to force the camera to update the register, then reads and returns the result. The refresh write is silently ignored on cameras that do not support it.

Returns:

Current buffer status. Possible values: DEACTIVATED, IDLE, HOLDING, RECORDING, UPDATING, TRANSMITTING, DEFRAGGING.

Return type:

reg.MemoryBufferStatus

Raises:

RuntimeError – If the camera is not connected.

buffer_recorded_frames(sequence: int = 0) int[source]#

Return the number of frames recorded in a sequence slot.

Writes the sequence selector register then reads REG_MEMORY_BUFFER_SEQ_RECORDED_SIZE.

Parameters:

sequence (int, optional) – 0-based sequence slot index. Default 0.

Returns:

Number of frames recorded in the selected sequence slot.

Return type:

int

Raises:
  • RuntimeError – If the camera is not connected.

  • GVCPError – If the camera rejects the register access, for example while the buffer is actively recording.

buffer_download(sequence: int = 0, start_frame: int | None = None, n_frames: int = 0, timeout: float = 0, bitrate_mbps: float | None = None, packet_size: int | None = None, strip_header: bool = True, convert: bool = True, verbose: bool = True, max_dropped_frames: int = 0, retries: int = 6, resend: bool = False) ndarray | None[source]#

Download frames from the internal memory buffer over Ethernet.

Sets the download mode to SEQUENCE, configures frame range and packet size, starts an acquisition stream, and collects frames via pyGigEVision.GVSPReceiver. The bitrate cap register is temporarily raised to bitrate_mbps to saturate the link, then restored on exit. Packet size and DoNotFragment flags are also restored after the transfer.

When convert is True and calibration mode is "RT", each frame is converted to degrees Celsius using the per-frame header’s DataExp and DataOffset fields (same path as grab()).

bitrate_mbps can be lowered (e.g. to 300) to reduce host network contention from other heavy network or CPU load during long transfers.

Parameters:
  • sequence (int, optional) – 0-based sequence slot index to download. Default 0.

  • start_frame (int or None, optional) – First frame ID to request. None (default) starts from the first recorded frame in the slot.

  • n_frames (int, optional) – Number of frames to download. 0 (default) downloads all recorded frames in the slot.

  • timeout (float, optional) – Per-pass timeout in seconds. 0 (default) auto-sizes each streaming pass from its frame count (1.5x the expected transfer time, minimum 10 s).

  • bitrate_mbps (float or None, optional) – Maximum download bitrate in Mbit/s written to the camera’s REG_DOWNLOAD_BITRATE_MAX register. None (default) auto-resolves: a value learned from earlier downloads this connection (lowered after drops) when auto_tune is on, otherwise 1000.0. Pass a number to override (e.g. 300 to ease network contention) and disable learning for this call.

  • packet_size (int or None, optional) – GVSP UDP payload size in bytes. None (default) auto-resolves: with auto_tune on, the largest size the path delivers is probed once per connection (jumbo when supported, else 1500) and cached; otherwise 1500. Pass a value to override. Sizes above 1500 need jumbo-frame support end-to-end (NIC/switches/OS MTU >= packet_size); when the path cannot carry the requested size the driver warns and falls back to 1500 rather than corrupting data.

  • strip_header (bool, optional) – Strip the two Telops metadata rows from each frame. Default True. Ignored when convert is True (stripping is implicit in the calibration path).

  • convert (bool, optional) – Apply calibration (strip headers and convert to Celsius in RT mode). Default True.

  • verbose (bool, optional) – Show a tqdm progress bar and log a transfer summary. Default True.

  • max_dropped_frames (int, optional) – Maximum number of incomplete frames tolerated before raising FrameIntegrityError. Default 0 (raise on any dropped or never-arrived frame). Pass a higher value or a large number to accept partial data.

  • retries (int, optional) – Maximum number of paced recovery rounds. After the first pass, any still-missing frames (never-arrived or incomplete) are re-streamed at a lower bitrate, repeating until the download is complete or this many rounds are spent. Frames persist in the camera buffer, so recovery converges. Default 6. Set to 0 for a single pass only.

  • resend (bool, optional) – Enable GVSP packet resends during the stream. Default False. Resends help on a lossy link with spare bandwidth, but during a saturated bulk transfer they can trigger congestion collapse, so bulk download keeps them off by default.

Returns:

Array of shape (N, H, W) where N is the number of frames received, H and W are the usable pixel dimensions. dtype is float32 when convert is True and RT mode is active; otherwise uint16. Returns None when no frames were recorded in the slot or no frames were received within the timeout.

Return type:

numpy.ndarray or None

Raises:

Examples

Download all frames from sequence 0 (default):

>>> frames = cam.buffer_download()
>>> frames.shape
(100, 254, 320)

Download a specific sequence (auto-tune selects the packet size):

>>> frames = cam.buffer_download(sequence=1)

Throttle transfer rate to reduce network contention:

>>> frames = cam.buffer_download(bitrate_mbps=300.0)
buffer_clear() None[source]#

Clear all recorded sequences from the memory buffer.

Writes 1 to REG_MEMORY_BUFFER_CLEAR_ALL. The camera wipes both the recorded frame data and the partition configuration (sequence count, sequence size, pre-MOI count, MOI source) as a side effect of the clear.

To keep the natural clear -> record -> download cycle working, this method automatically re-applies the last-used buffer_configure() parameters (with a short settle delay) after clearing. If buffer_configure() has not been called in this session, only the clear register write is performed.

Raises:

RuntimeError – If the camera is not connected.

live_view(colormap: str = 'inferno', scale: int = 2) None[source]#

Open a live thermal image viewer window.

Launches the pyTelops.gui.LiveView Tk-based viewer, which grabs frames from the camera and displays them in real time using the specified colormap. The call blocks until the viewer window is closed.

Requires the gui optional dependency group:

pip install pyTelops[gui]
Parameters:
  • colormap (str, optional) – Matplotlib colormap name applied to the thermal image. Default "inferno".

  • scale (int, optional) – Integer upscale factor applied to each dimension of the displayed image. 2 (default) doubles the width and height.

Raises:
read_register(addr: int) int[source]#

Read a raw 32-bit integer register value.

Low-level escape hatch that issues a GVCP ReadReg command directly for a given register address. Prefer the typed properties (e.g. frame_rate, integration_time) for routine use.

Parameters:

addr (int) – 32-bit register address (byte offset from the GVCP bootstrap base, as defined in pyTelops.registers).

Returns:

The 32-bit unsigned integer value read from the register.

Return type:

int

Raises:
  • RuntimeError – If the camera is not connected.

  • GVCPError – If the camera returns an error response for the address.

write_register(addr: int, value: int) None[source]#

Write a raw 32-bit integer value to a register.

Low-level escape hatch that issues a GVCP WriteReg command directly. Prefer the typed properties for routine use.

Parameters:
  • addr (int) – 32-bit register address (byte offset from the GVCP bootstrap base, as defined in pyTelops.registers).

  • value (int) – 32-bit unsigned integer value to write.

Raises:
  • RuntimeError – If the camera is not connected.

  • GVCPError – If the camera returns an error response for the address.

read_float_register(addr: int) float[source]#

Read a register and interpret its bits as an IEEE 754 float.

Uses pyGigEVision.GVCPClient.read_float() to reinterpret the raw 32-bit register value as a single-precision float via struct.unpack. Use for camera registers that store floating- point values (e.g. frame rate, temperature setpoints).

Parameters:

addr (int) – 32-bit register address (byte offset from the GVCP bootstrap base, as defined in pyTelops.registers).

Returns:

The register value interpreted as an IEEE 754 single-precision float.

Return type:

float

Raises:
  • RuntimeError – If the camera is not connected.

  • GVCPError – If the camera returns an error response for the address.

write_float_register(addr: int, value: float) None[source]#

Write a float value to a register as IEEE 754 bits.

Uses pyGigEVision.GVCPClient.write_float() to pack value as a single-precision float via struct.pack before writing.

Parameters:
  • addr (int) – 32-bit register address (byte offset from the GVCP bootstrap base, as defined in pyTelops.registers).

  • value (float) – Value to write, encoded as an IEEE 754 single-precision float.

Raises:
  • RuntimeError – If the camera is not connected.

  • GVCPError – If the camera returns an error response for the address.

Module-level helpers#

pyTelops.discover(interface_ip: str = '', timeout: float = 2.0, all_vendors: bool = False) list[dict][source]#

Discover Telops cameras on the network.

Sends a GVCP broadcast and collects responses from all host interfaces via the protocol layer. By default only Telops cameras are returned – responses from other GigE Vision devices (FLIR, Basler, Allied Vision, laser scanners, etc.) that happen to share the network are filtered out by manufacturer string. Pass all_vendors=True to get every discovered GigE Vision device regardless of vendor.

Parameters:
  • interface_ip (str) – Local IP to bind to (empty string = broadcast on all interfaces).

  • timeout (float) – Seconds to wait for responses.

  • all_vendors (bool) – If True, return every GigE Vision camera found, not just Telops ones. Useful for debugging network setup when you want to see what is out there. Defaults to False.

Returns:

Each dict has keys:

ip

IPv4 address of the camera.

manufacturer

Manufacturer name string from the camera.

model

Model name string from the camera.

device_version

Firmware or device version string.

serial

Serial number string.

user_name

User-assigned name string (may be empty).

mac

MAC address of the camera’s network interface.

reachable

True if the camera IP falls within a subnet of a host NIC, False if it is on an unreachable subnet.

interface_ip

IP address of the local host interface that received the discovery reply from this camera. Empty string when not reported by the protocol layer.

Return type:

list of dict

Provisioning and tuning#

pyTelops.force_ip(camera: dict, ip: str, mask: str, gateway: str | None = None) None[source]#

Assign a new IP to a discovered camera by MAC, via GVCP FORCEIP.

Re-homes a camera that is on the wrong subnet (or fell back to link-local) without changing host NIC configuration. The camera reboots its IP stack; re-run pyTelops.discover() afterwards to see the new address.

Parameters:
  • camera (dict) – A camera dict from pyTelops.discover() (must contain "mac").

  • ip (str) – New IPv4 address and subnet mask for the camera.

  • mask (str) – New IPv4 address and subnet mask for the camera.

  • gateway (str or None, optional) – Default gateway, or None for none.

pyTelops.tune_connection(cam, probe_only=False, candidate_packet_sizes=None, candidate_bitrates=None, socket_buffers=None, test_frames=300, read_nic_info=False)[source]#

Probe the link and sweep download settings to find a stable+fast config.

Phase 1 probes the path (read-only). With probe_only, returns after the probe. Phase 2 runs real downloads across candidate settings and ranks them stability-first. No system or camera settings are persisted or mutated.

Parameters:
  • cam (Camera) – A connected Telops camera with frames already in its memory buffer (record a sequence before sweeping).

  • probe_only (bool, optional) – Stop after the read-only probe; run no downloads. Default False.

  • candidate_packet_sizes (list or None) – Values to sweep. None picks sensible defaults (packet sizes capped at the probed path maximum).

  • candidate_bitrates (list or None) – Values to sweep. None picks sensible defaults (packet sizes capped at the probed path maximum).

  • socket_buffers (list or None) – Values to sweep. None picks sensible defaults (packet sizes capped at the probed path maximum).

  • test_frames (int, optional) – Frames per trial download. Default 300.

  • read_nic_info (bool, optional) – Read (never change) host NIC facts to annotate the report. Default False. Requires psutil.

Return type:

ConnectionReport

Errors and results#

class pyTelops.ConnectionReport(recommended: dict, sweep: list[TrialResult] = <factory>, probe: ProbeInfo | None = None, warnings: list[str] = <factory>)[source]#

Bases: object

Result of tune_connection().

recommended: dict#
sweep: list[TrialResult]#
probe: ProbeInfo | None = None#
warnings: list[str]#
classmethod from_trials(trials, probe, warnings)[source]#
apply(cam)[source]#

Store the recommended kwargs on cam for later buffer_download calls.

Does not change any system or camera setting; just records the recommendation as cam.recommended_download_kwargs.

class pyTelops.DownloadStats(n_frames: int, n_incomplete: int = 0, incomplete_frame_ids: list[int] = <factory>, per_frame_missing: dict[int, int]=<factory>, resend_requested: int = 0, resend_recovered: int = 0, resend_failed: int = 0, recovered_by_retry: int = 0, first_pass_n_complete: int = 0, throughput_mbps: float = 0.0, elapsed_s: float = 0.0, packet_size_used: int = 1500, bitrate_used: float = 0.0)[source]#

Bases: object

Integrity and performance report for one buffer download.

Populated by pyTelops.Camera.buffer_download() and attached to pyTelops.Camera.last_download_stats.

n_frames: int#
n_incomplete: int = 0#
incomplete_frame_ids: list[int]#
per_frame_missing: dict[int, int]#
resend_requested: int = 0#
resend_recovered: int = 0#
resend_failed: int = 0#
recovered_by_retry: int = 0#
first_pass_n_complete: int = 0#
throughput_mbps: float = 0.0#
elapsed_s: float = 0.0#
packet_size_used: int = 1500#
bitrate_used: float = 0.0#
exception pyTelops.FrameIntegrityError(message: str, stats: DownloadStats)[source]#

Bases: Exception

Raised when frames remain incomplete after resends and retries.

Carries the DownloadStats so callers can inspect exactly which frames were affected.

Enumerations#

Telops-specific register addresses and IntEnum value mappings for the FAST M3k camera.

All constants are derived from the camera’s GenICam XML descriptor (CommonTEL2000LibProject.xml v12.7.1, downloaded directly from the camera). Register values are 4 bytes each; integers use big-endian uint32 (>I) encoding and floats use big-endian IEEE 754 (>f) encoding.

class pyTelops.registers.CalibrationMode(value)[source]#

Bases: IntEnum

Output calibration applied to each frame (RAW, NUC, radiometric temperature, radiance).

RAW0 = 0#
RAW = 255#
NUC = 1#
RT = 2#
IBR = 3#
IBI = 4#
class pyTelops.registers.ExposureAuto(value)[source]#

Bases: IntEnum

Automatic exposure control mode (off, single-shot, or continuous).

OFF = 0#
ONCE = 1#
CONTINUOUS = 2#
class pyTelops.registers.ExposureMode(value)[source]#

Bases: IntEnum

How the sensor integration time is determined (timed, trigger-width, etc.).

OFF = 0#
TIMED = 1#
TRIGGER_WIDTH = 2#
TRIGGER_CONTROLLED = 3#
class pyTelops.registers.AcquisitionMode(value)[source]#

Bases: IntEnum

Frame acquisition mode (continuous, single, or multi-frame burst).

CONTINUOUS = 0#
SINGLE_FRAME = 1#
MULTI_FRAME = 2#
class pyTelops.registers.TriggerSelector(value)[source]#

Bases: IntEnum

Which trigger function is targeted by TriggerMode/TriggerSource settings.

ACQUISITION_START = 0#
FLAGGING = 1#
GATING = 2#
class pyTelops.registers.TriggerMode(value)[source]#

Bases: IntEnum

Enable or disable the selected trigger function.

OFF = 0#
ON = 1#
class pyTelops.registers.TriggerSource(value)[source]#

Bases: IntEnum

Signal source for the selected trigger (software command or BNC external input).

SOFTWARE = 0#
EXTERNAL_SIGNAL = 48#
class pyTelops.registers.TriggerActivation(value)[source]#

Bases: IntEnum

Edge or level polarity that activates the selected trigger.

RISING_EDGE = 0#
FALLING_EDGE = 1#
ANY_EDGE = 2#
LEVEL_HIGH = 3#
LEVEL_LOW = 4#
class pyTelops.registers.MemoryBufferMode(value)[source]#

Bases: IntEnum

Enable or disable the onboard 16 GB memory buffer.

OFF = 0#
ON = 1#
class pyTelops.registers.MemoryBufferStatus(value)[source]#

Bases: IntEnum

Current operational state of the onboard memory buffer.

DEACTIVATED = 0#
IDLE = 1#
HOLDING = 2#
RECORDING = 3#
UPDATING = 4#
TRANSMITTING = 5#
DEFRAGGING = 6#
REFRESH = 255#
class pyTelops.registers.MemoryBufferDownloadMode(value)[source]#

Bases: IntEnum

Unit of download from the onboard buffer (off, full sequence, or single image).

OFF = 0#
SEQUENCE = 1#
IMAGE = 2#
class pyTelops.registers.MemoryBufferMOISource(value)[source]#

Bases: IntEnum

Event source that marks the moment-of-interest (MOI) in a buffer recording.

ACQUISITION_STARTED = 0#
SOFTWARE = 1#
EXTERNAL_SIGNAL = 2#
NONE = 255#
class pyTelops.registers.MemoryBufferMOIActivation(value)[source]#

Bases: IntEnum

Edge polarity used to detect the moment-of-interest signal.

RISING_EDGE = 0#
FALLING_EDGE = 1#
ANY_EDGE = 2#
class pyTelops.registers.IntegrationMode(value)[source]#

Bases: IntEnum

Timing relationship between sensor integration and readout phases.

INTEGRATE_THEN_READ = 0#
INTEGRATE_WHILE_READ = 1#
class pyTelops.registers.DetectorMode(value)[source]#

Bases: IntEnum

Detector operating mode (normal continuous or high-speed burst).

NORMAL = 0#
BURST = 1#
class pyTelops.registers.SensorWellDepth(value)[source]#

Bases: IntEnum

Detector well-depth selection, trading dynamic range for gain.

LOW_GAIN = 0#
HIGH_GAIN = 1#
class pyTelops.registers.DevicePowerState(value)[source]#

Bases: IntEnum

Camera power state (standby, fully on, or transitioning between states).

STANDBY = 0#
ON = 1#
IN_TRANSITION = 2#
class pyTelops.registers.PixelFormat(value)[source]#

Bases: IntEnum

GigE Vision pixel format codes for the camera output stream.

MONO8 = 17301505#
MONO16 = 17825799#
MONO10 = 17825795#
MONO12 = 17825797#
MONO14 = 17825829#
class pyTelops.registers.ImageCorrectionMode(value)[source]#

Bases: IntEnum

Reference source used when performing non-uniformity correction (NUC).

BLACK_BODY = 0#
ICU = 1#
class pyTelops.registers.TestImageSelector(value)[source]#

Bases: IntEnum

Built-in test pattern injected instead of live sensor data.

OFF = 0#
STATIC_SHADE = 30#
DYNAMIC_SHADE = 31#
CONSTANT_VALUE = 35#
class pyTelops.registers.FrameRateMode(value)[source]#

Bases: IntEnum

Frame rate control strategy (fixed, locked to trigger, maximum, or burst).

FIXED_LOCKED = 0#
FIXED = 1#
MAXIMUM = 2#
BURST = 3#
class pyTelops.registers.TemperatureLocation(value)[source]#

Bases: IntEnum

Selects which internal sensor reports its temperature via the diagnostic register.

SENSOR = 0#
MAINBOARD = 1#
INTERNAL_LENS = 2#
EXTERNAL_LENS = 3#
ICU = 4#
FILTER_WHEEL = 5#
COMPRESSOR = 6#
COLD_FINGER = 7#
SPARE = 8#
EXTERNAL_THERMISTOR = 9#
PROCESSING_FPGA = 10#
OUTPUT_FPGA = 11#
STORAGE_FPGA = 12#
class pyTelops.registers.VoltageLocation(value)[source]#

Bases: IntEnum

Selects which power rail is read by the voltage diagnostic register.

COOLER = 10#
SUPPLY_24V = 11#
class pyTelops.registers.CurrentLocation(value)[source]#

Bases: IntEnum

Selects which current measurement is read by the current diagnostic register.

COOLER = 0#
SUPPLY_24V = 1#
class pyTelops.registers.CalibrationCollectionType(value)[source]#

Bases: IntEnum

Type identifier for a stored calibration collection (currently only Telops-fixed).

TELOPS_FIXED = 0#