PlatSim_Genova/TestEnvironment/env/site-packages/pyvisa/events.py
2026-01-30 16:38:33 +01:00

238 lines
7.6 KiB
Python

# -*- coding: utf-8 -*-
"""VISA events with convenient access to the available attributes.
This file is part of PyVISA.
:copyright: 2020-2022 by PyVISA Authors, see AUTHORS for more details.
:license: MIT, see LICENSE for more details.
"""
from typing import TYPE_CHECKING, Callable, Dict, Optional, Type
from typing_extensions import ClassVar
from . import attributes, constants, errors, logger
from .attributes import Attribute
from .typing import Any, VISAEventContext, VISAJobID
if TYPE_CHECKING:
from . import highlevel # pragma: no cover
class Event:
"""Event that lead to the call of an event handler.
Do not instantiate directly use the visa_event context manager of the
Resource object passed to the handler.
Notes
-----
When using the queuing mechanism events are expected to be closed manually
after handling them.
When using callbacks, the events should only be closed if VISA will never
get control again which since we always attempt to properly close all
resources should never happend and hence events should never be closed manually.
"""
#: Reference to the visa library
visalib: "highlevel.VisaLibraryBase"
#: Type of the event.
event_type: constants.EventType
#: Context use to query the event attributes.
_context: Optional[VISAEventContext]
#: Maps Event type to Python class encapsulating that event.
_event_classes: ClassVar[Dict[constants.EventType, Type["Event"]]] = dict()
@classmethod
def register(
cls, event_type: constants.EventType
) -> Callable[[Type["Event"]], Type["Event"]]:
"""Register a class with a given event type."""
def _internal(python_class: Type["Event"]) -> Type["Event"]:
if event_type in cls._event_classes:
logger.warning(
"%s is already registered. "
"Overwriting with %s" % (event_type, python_class)
)
for attr in attributes.AttributesPerResource[event_type]:
if not hasattr(python_class, attr.py_name):
raise TypeError(
"%s is expected to have an attribute %s"
% (python_class, attr.py_name)
)
cls._event_classes[event_type] = python_class
return python_class
return _internal
def __new__(
cls,
visalib: "highlevel.VisaLibraryBase",
event_type: constants.EventType,
context: VISAEventContext,
) -> "Event":
event_cls = cls._event_classes.get(event_type, Event)
return object.__new__(event_cls)
def __init__(
self,
visalib: "highlevel.VisaLibraryBase",
event_type: constants.EventType,
context: Optional[VISAEventContext],
) -> None:
self.visalib = visalib
self.event_type = event_type
self._context = context
@property
def context(self) -> VISAEventContext:
"""Access the VISA context used to retrieve attributes.
This is equivalent to the session on a resource.
"""
c = self._context
if c is None:
raise errors.InvalidSession()
return c
def get_visa_attribute(self, attribute_id: constants.EventAttribute) -> Any:
"""Get the specified VISA attribute."""
return self.visalib.get_attribute(self.context, attribute_id)[0]
def close(self):
"""Simply invalidate the context.
The event is not closed since it is only ever required when using
the queue mechanism and this is handled in WaitResponse.
"""
self._context = None
# Those events do not have any payload beyond their type, for those use the base class
for event in (
constants.EventType.clear,
constants.EventType.service_request,
constants.EventType.gpib_listen,
constants.EventType.gpib_talk,
constants.EventType.vxi_vme_sysfail,
constants.EventType.vxi_vme_sysreset,
):
Event.register(event)(Event)
@Event.register(constants.EventType.exception)
class ExceptionEvent(Event):
"""Event corresponding to an exception."""
#: Status code of the operation that generated the exception
status: Attribute[constants.StatusCode] = attributes.AttrVI_ATTR_STATUS()
#: Name of the operation that led to the exception
operation_name: Attribute[str] = attributes.AttrVI_ATTR_OPER_NAME()
@Event.register(constants.EventType.gpib_controller_in_charge)
class GPIBCICEvent(Event):
"""GPIB Controller in Charge event.
The event is emitted if the status is gained or lost.
"""
#: New state of the controller in charge status
cic_state: Attribute[
constants.LineState
] = attributes.AttrVI_ATTR_GPIB_RECV_CIC_STATE()
@Event.register(constants.EventType.io_completion)
class IOCompletionEvent(Event):
"""Event marking the completion of an IO operation."""
#: Status code of the asynchronous I/O operation that has completed.
status: Attribute[constants.StatusCode] = attributes.AttrVI_ATTR_STATUS()
#: Buffer that was used in an asynchronous operation.
buffer: Attribute[bytes] = attributes.AttrVI_ATTR_BUFFER()
#: Actual number of elements that were asynchronously transferred.
return_count: Attribute[int] = attributes.AttrVI_ATTR_RET_COUNT()
#: Name of the operation generating the event.
operation_name: Attribute[str] = attributes.AttrVI_ATTR_OPER_NAME()
#: Job ID of the asynchronous operation that has completed.
job_id: Attribute[VISAJobID] = attributes.AttrVI_ATTR_JOB_ID()
@property
def data(self):
"""Portion of the buffer that was actually filled during the call."""
return bytes(self.buffer[: self.return_count])
@Event.register(constants.EventType.trig)
class TrigEvent(Event):
"""Trigger event."""
#: Identifier of the triggering mechanism on which the specified trigger event
#: was received.
received_trigger_id: Attribute[
constants.TriggerID
] = attributes.AttrVI_ATTR_TRIG_ID()
@Event.register(constants.EventType.usb_interrupt)
class USBInteruptEvent(Event):
"""USB interruption event."""
#: Status of the read operation from the USB interrupt-IN pipe.
status: Attribute[constants.StatusCode] = attributes.AttrVI_ATTR_STATUS()
#: Size of the data that was received from the USB interrupt-IN pipe.
size: Attribute[int] = attributes.AttrVI_ATTR_USB_RECV_INTR_SIZE()
#: Actual data that was received from the USB interrupt-IN pipe.
data = attributes.AttrVI_ATTR_USB_RECV_INTR_DATA()
@Event.register(constants.EventType.vxi_signal_interrupt)
class VXISignalInteruptEvent(Event):
"""VXI signal event."""
#: 16-bit Status/ID value retrieved during the IACK cycle or
#: from the Signal register.
signal_register_status_id: Attribute[int] = attributes.AttrVI_ATTR_SIGP_STATUS_ID()
@Event.register(constants.EventType.vxi_vme_interrupt)
class VXIInterruptEvent(Event):
"""VXI interrupt event."""
#: 32-bit status/ID retrieved during the IACK cycle.
status_id: Attribute[int] = attributes.AttrVI_ATTR_INTR_STATUS_ID()
#: VXI interrupt level on which the interrupt was received.
level: Attribute[int] = attributes.AttrVI_ATTR_RECV_INTR_LEVEL()
@Event.register(constants.EventType.pxi_interrupt)
class PXIInteruptEvent(Event):
"""PXI interruption event."""
#: Index of the interrupt sequence that detected the interrupt condition.
sequence: Attribute[int] = attributes.AttrVI_ATTR_PXI_RECV_INTR_SEQ()
#: First PXI/PCI register read in the successful interrupt detection sequence.
data: Attribute[int] = attributes.AttrVI_ATTR_PXI_RECV_INTR_DATA()