BioImager  4.9.0
A .NET microscopy imaging application based on Bio library. Supports various microscopes by using imported libraries & GUI automation. Supports XInput game controllers to move stage, take images, run ImageJ macros on images or Bio C# scripts.
Loading...
Searching...
No Matches
microscope.abc.DataDevice Class Reference
Inheritance diagram for microscope.abc.DataDevice:
microscope.abc.Device microscope.abc.Camera microscope.cameras.andorsdk3.AndorSDK3 microscope.cameras.atmcd.AndorAtmcd microscope.cameras.picam.PiCamera microscope.cameras.pvcam.PVCamera microscope.cameras.ximea.XimeaCamera microscope.simulators.SimulatedCamera microscope.simulators.stage_aware_camera.StageAwareCamera microscope.testsuite.devices.TestCamera

Public Member Functions

None __init__ (self, int buffer_length=0, **kwargs)
 
 __del__ (self)
 
None abort (self)
 
None enable (self)
 
None disable (self)
 
None set_client (self, new_client)
 
None update_settings (self, settings, bool init=False)
 
None receiveClient (self, str client_uri)
 
 grab_next_data (self, bool soft_trigger=True)
 
None receiveData (self, data, timestamp)
 
- Public Member Functions inherited from microscope.abc.Device
bool get_is_enabled (self)
 
None initialize (self)
 
None shutdown (self)
 
None add_setting (self, name, dtype, get_func, set_func, values, typing.Optional[typing.Callable[[], bool]] readonly=None)
 
 get_setting (self, str name)
 
 get_all_settings (self)
 
None set_setting (self, str name, value)
 
 describe_setting (self, str name)
 
 describe_settings (self)
 

Public Attributes

bool enabled = False
 
bool _fetch_thread = True
 
bool _dispatch_thread = True
 
None _fetch_thread_run = self._fetch_data()
 
- Public Attributes inherited from microscope.abc.Device
bool enabled = False
 

Static Public Attributes

 set_setting = keep_acquiring(Device.set_setting)
 

Protected Member Functions

None _fetch_data (self)
 
 _process_data (self, data)
 
 _send_data (self, client, data, timestamp)
 
None _dispatch_loop (self)
 
None _fetch_loop (self)
 
 _client (self)
 
 _client (self, val)
 
None _put (self, data, timestamp)
 
- Protected Member Functions inherited from microscope.abc.Device
 _do_disable (self)
 
 _do_enable (self)
 
None _do_shutdown (self)
 

Protected Attributes

 _fetch_thread = None
 
bool _fetch_thread_run = False
 
bool _using_callback = False
 
list _clientStack = []
 
 _liveClients = set()
 
 _dispatch_thread = None
 
 _dispatch_buffer = queue.Queue(maxsize=buffer_length)
 
bool _acquiring = False
 
 _new_data_condition = threading.Condition()
 
 _client = None
 
tuple _new_data = (data, timestamp)
 
- Protected Attributes inherited from microscope.abc.Device
dict _settings = {}
 

Detailed Description

A data capture device.

This class handles a thread to fetch data from a device and dispatch
it to a client.  The client is set using set_client(uri) or (legacy)
receiveClient(uri).

Derived classed should implement::

* :meth:`abort` (required)
* :meth:`_fetch_data` (required)
* :meth:`_process_data` (optional)

Derived classes may override `__init__`, `enable` and `disable`,
but must ensure to call this class's implementations as indicated
in the docstrings.

Definition at line 539 of file abc.py.

Constructor & Destructor Documentation

◆ __init__()

None microscope.abc.DataDevice.__init__ ( self,
int buffer_length = 0,
** kwargs )
Derived.__init__ must call this at some point.

Reimplemented from microscope.abc.Device.

Reimplemented in microscope.abc.Camera, microscope.cameras.picam.PiCamera, microscope.cameras.ximea.XimeaCamera, microscope.simulators.SimulatedCamera, microscope.simulators.stage_aware_camera.StageAwareCamera, and microscope.testsuite.devices.TestCamera.

Definition at line 558 of file abc.py.

558 def __init__(self, buffer_length: int = 0, **kwargs) -> None:
559 """Derived.__init__ must call this at some point."""
560 super().__init__(**kwargs)
561 # A thread to fetch and dispatch data.
562 self._fetch_thread = None
563 # A flag to control the _fetch_thread.
564 self._fetch_thread_run = False
565 # A flag to indicate that this class uses a fetch callback.
566 self._using_callback = False
567 # Clients to which we send data.
568 self._clientStack = []
569 # A set of live clients to avoid repeated dispatch to disconnected client.
570 self._liveClients = set()
571 # A thread to dispatch data.
572 self._dispatch_thread = None
573 # A buffer for data dispatch.
574 self._dispatch_buffer = queue.Queue(maxsize=buffer_length)
575 # A flag to indicate if device is ready to acquire.
576 self._acquiring = False
577 # A condition to signal arrival of a new data and unblock grab_next_data
578 self._new_data_condition = threading.Condition()
579

◆ __del__()

microscope.abc.DataDevice.__del__ ( self)

Reimplemented from microscope.abc.Device.

Definition at line 580 of file abc.py.

580 def __del__(self):
581 self.disable()
582 super().__del__()
583

Member Function Documentation

◆ _client() [1/2]

microscope.abc.DataDevice._client ( self)
protected
A getter for the current client.

Definition at line 732 of file abc.py.

732 def _client(self):
733 """A getter for the current client."""
734 return (self._clientStack or [None])[-1]
735

◆ _client() [2/2]

microscope.abc.DataDevice._client ( self,
val )
protected
Push or pop a client from the _clientStack.

Definition at line 737 of file abc.py.

737 def _client(self, val):
738 """Push or pop a client from the _clientStack."""
739 if val is None:
740 self._clientStack.pop()
741 else:
742 self._clientStack.append(val)
743 self._liveClients = set(self._clientStack)
744

◆ _dispatch_loop()

None microscope.abc.DataDevice._dispatch_loop ( self)
protected
Process data and send results to any client.

Definition at line 684 of file abc.py.

684 def _dispatch_loop(self) -> None:
685 """Process data and send results to any client."""
686 while True:
687 client, data, timestamp = self._dispatch_buffer.get(block=True)
688 if client not in self._liveClients:
689 continue
690 err = None
691 if isinstance(data, Exception):
692 standard_exception = Exception(str(data).encode("ascii"))
693 try:
694 self._send_data(client, standard_exception, timestamp)
695 except Exception as e:
696 err = e
697 else:
698 try:
699 self._send_data(
700 client, self._process_data(data), timestamp
701 )
702 except Exception as e:
703 err = e
704 if err:
705 # Raising an exception will kill the dispatch loop. We need
706 # another way to notify the client that there was a problem.
707 _logger.error("in _dispatch_loop:", exc_info=err)
708 self._dispatch_buffer.task_done()
709

◆ _fetch_data()

None microscope.abc.DataDevice._fetch_data ( self)
protected
Poll for data and return it, with minimal processing.

If the device uses buffering in software, this function should
copy the data from the buffer, release or recycle the buffer,
then return a reference to the copy.  Otherwise, if the SDK
returns a data object that will not be written to again, this
function can just return a reference to the object.  If no
data is available, return `None`.

Reimplemented in microscope.cameras.andorsdk3.AndorSDK3, microscope.cameras.atmcd.AndorAtmcd, microscope.cameras.picam.PiCamera, microscope.cameras.pvcam.PVCamera, microscope.cameras.ximea.XimeaCamera, microscope.simulators.SimulatedCamera, and microscope.simulators.stage_aware_camera.StageAwareCamera.

Definition at line 643 of file abc.py.

643 def _fetch_data(self) -> None:
644 """Poll for data and return it, with minimal processing.
645
646 If the device uses buffering in software, this function should
647 copy the data from the buffer, release or recycle the buffer,
648 then return a reference to the copy. Otherwise, if the SDK
649 returns a data object that will not be written to again, this
650 function can just return a reference to the object. If no
651 data is available, return `None`.
652
653 """
654 return None
655

◆ _fetch_loop()

None microscope.abc.DataDevice._fetch_loop ( self)
protected
Poll source for data and put it into dispatch buffer.

Definition at line 710 of file abc.py.

710 def _fetch_loop(self) -> None:
711 """Poll source for data and put it into dispatch buffer."""
712 self._fetch_thread_run = True
713
714 while self._fetch_thread_run:
715 try:
716 data = self._fetch_data()
717 except Exception as e:
718 _logger.error("in _fetch_loop:", exc_info=e)
719 # Raising an exception will kill the fetch loop. We need
720 # another way to notify the client that there was a problem.
721 timestamp = time.time()
722 self._put(e, timestamp)
723 data = None
724 if data is not None:
725 # TODO Add support for timestamp from hardware.
726 timestamp = time.time()
727 self._put(data, timestamp)
728 else:
729 time.sleep(0.001)
730

◆ _process_data()

microscope.abc.DataDevice._process_data ( self,
data )
protected
Do any data processing and return data.

Reimplemented in microscope.abc.Camera.

Definition at line 656 of file abc.py.

656 def _process_data(self, data):
657 """Do any data processing and return data."""
658 return data
659

◆ _put()

None microscope.abc.DataDevice._put ( self,
data,
timestamp )
protected
Put data and timestamp into dispatch buffer with target dispatch client.

Definition at line 745 of file abc.py.

745 def _put(self, data, timestamp) -> None:
746 """Put data and timestamp into dispatch buffer with target dispatch client."""
747 self._dispatch_buffer.put((self._client, data, timestamp))
748

◆ _send_data()

microscope.abc.DataDevice._send_data ( self,
client,
data,
timestamp )
protected
Dispatch data to the client.

Definition at line 660 of file abc.py.

660 def _send_data(self, client, data, timestamp):
661 """Dispatch data to the client."""
662 try:
663 # Cockpit will send a client with receiveData and expects
664 # two arguments (data and timestamp). But we really want
665 # to use Python's Queue and instead of just the timestamp
666 # we should be sending some proper metadata object. We
667 # don't have that proper metadata class yet so just send
668 # the image data as a numpy ndarray for now.
669 if hasattr(client, "put"):
670 client.put(data)
671 else:
672 client.receiveData(data, timestamp)
673 except (
674 Pyro4.errors.ConnectionClosedError,
675 Pyro4.errors.CommunicationError,
676 ):
677 # Client not listening
678 _logger.info(
679 "Removing %s from client stack: disconnected.", client._pyroUri
680 )
681 self._clientStack = list(filter(client.__ne__, self._clientStack))
682 self._liveClients = self._liveClients.difference([client])
683

◆ abort()

None microscope.abc.DataDevice.abort ( self)
Stop acquisition as soon as possible.

Reimplemented in microscope.cameras.andorsdk3.AndorSDK3, microscope.cameras.atmcd.AndorAtmcd, microscope.cameras.picam.PiCamera, microscope.cameras.pvcam.PVCamera, microscope.cameras.ximea.XimeaCamera, and microscope.simulators.SimulatedCamera.

Definition at line 588 of file abc.py.

588 def abort(self) -> None:
589 """Stop acquisition as soon as possible."""
590 self._acquiring = False
591

◆ disable()

None microscope.abc.DataDevice.disable ( self)
Disable the data capture device.

Implement device-specific code in `_do_disable`.

Reimplemented from microscope.abc.Device.

Definition at line 629 of file abc.py.

629 def disable(self) -> None:
630 """Disable the data capture device.
631
632 Implement device-specific code in `_do_disable`.
633
634 """
635 self.enabled = False
636 if self._fetch_thread:
637 if self._fetch_thread.is_alive():
638 self._fetch_thread_run = False
639 self._fetch_thread.join()
640 super().disable()
641

◆ enable()

None microscope.abc.DataDevice.enable ( self)
Enable the data capture device.

Ensures that a data handling threads are running.  Implement
device specific code in `_do_enable`.

Reimplemented from microscope.abc.Device.

Definition at line 592 of file abc.py.

592 def enable(self) -> None:
593 """Enable the data capture device.
594
595 Ensures that a data handling threads are running. Implement
596 device specific code in `_do_enable`.
597
598 """
599 _logger.debug("Enabling ...")
600 # Call device-specific code.
601 try:
602 result = self._do_enable()
603 except Exception as err:
604 _logger.debug("Error in _do_enable:", exc_info=err)
605 self.enabled = False
606 raise err
607 if not result:
608 self.enabled = False
609 else:
610 self.enabled = True
611 # Set up data fetching
612 if self._using_callback:
613 if self._fetch_thread:
614 self._fetch_thread_run = False
615 else:
616 if not self._fetch_thread or not self._fetch_thread.is_alive():
617 self._fetch_thread = Thread(target=self._fetch_loop)
618 self._fetch_thread.daemon = True
619 self._fetch_thread.start()
620 if (
621 not self._dispatch_thread
622 or not self._dispatch_thread.is_alive()
623 ):
624 self._dispatch_thread = Thread(target=self._dispatch_loop)
625 self._dispatch_thread.daemon = True
626 self._dispatch_thread.start()
627 _logger.debug("... enabled.")
628

◆ grab_next_data()

microscope.abc.DataDevice.grab_next_data ( self,
bool soft_trigger = True )
Returns results from next trigger via a direct call.

Args:
    soft_trigger: calls :meth:`trigger` if `True`, waits for
        hardware trigger if `False`.

Definition at line 789 of file abc.py.

789 def grab_next_data(self, soft_trigger: bool = True):
790 """Returns results from next trigger via a direct call.
791
792 Args:
793 soft_trigger: calls :meth:`trigger` if `True`, waits for
794 hardware trigger if `False`.
795
796 """
797 if not self.enabled:
798 raise microscope.DisabledDeviceError("Camera not enabled.")
799 self._new_data_condition.acquire()
800 # Push self onto client stack.
801 self.set_client(self)
802 # Wait for data from next trigger.
803 if soft_trigger:
804 self.trigger()
805 self._new_data_condition.wait()
806 # Pop self from client stack
807 self.set_client(None)
808 # Return the data.
809 return self._new_data
810

◆ receiveClient()

None microscope.abc.DataDevice.receiveClient ( self,
str client_uri )
A passthrough for compatibility.

Definition at line 785 of file abc.py.

785 def receiveClient(self, client_uri: str) -> None:
786 """A passthrough for compatibility."""
787 self.set_client(client_uri)
788

◆ receiveData()

None microscope.abc.DataDevice.receiveData ( self,
data,
timestamp )
Unblocks grab_next_frame so it can return.

Definition at line 812 of file abc.py.

812 def receiveData(self, data, timestamp) -> None:
813 """Unblocks grab_next_frame so it can return."""
814 with self._new_data_condition:
815 self._new_data = (data, timestamp)
816 self._new_data_condition.notify()
817
818

◆ set_client()

None microscope.abc.DataDevice.set_client ( self,
new_client )
Set up a connection to our client.

Clients now sit in a stack so that a single device may send
different data to multiple clients in a single experiment.
The usage is currently::

    device.set_client(client) # Add client to top of stack
    # do stuff, send triggers, receive data
    device.set_client(None)   # Pop top client off stack.

There is a risk that some other client calls ``None`` before
the current client is finished.  Avoiding this will require
rework here to identify the caller and remove only that caller
from the client stack.

Definition at line 749 of file abc.py.

749 def set_client(self, new_client) -> None:
750 """Set up a connection to our client.
751
752 Clients now sit in a stack so that a single device may send
753 different data to multiple clients in a single experiment.
754 The usage is currently::
755
756 device.set_client(client) # Add client to top of stack
757 # do stuff, send triggers, receive data
758 device.set_client(None) # Pop top client off stack.
759
760 There is a risk that some other client calls ``None`` before
761 the current client is finished. Avoiding this will require
762 rework here to identify the caller and remove only that caller
763 from the client stack.
764
765 """
766 if new_client is not None:
767 if isinstance(new_client, (str, Pyro4.core.URI)):
768 self._client = Pyro4.Proxy(new_client)
769 else:
770 self._client = new_client
771 else:
772 self._client = None
773 # _client uses a setter. Log the result of assignment.
774 if self._client is None:
775 _logger.info("Current client is None.")
776 else:
777 _logger.info("Current client is %s.", str(self._client))
778

◆ update_settings()

None microscope.abc.DataDevice.update_settings ( self,
settings,
bool init = False )
Update settings, toggling acquisition if necessary.

Reimplemented from microscope.abc.Device.

Definition at line 780 of file abc.py.

780 def update_settings(self, settings, init: bool = False) -> None:
781 """Update settings, toggling acquisition if necessary."""
782 super().update_settings(settings, init)
783

Member Data Documentation

◆ _acquiring

bool microscope.abc.DataDevice._acquiring = False
protected

Reimplemented in microscope.cameras.atmcd.AndorAtmcd.

Definition at line 576 of file abc.py.

◆ _client

microscope.abc.DataDevice._client = None
protected

Definition at line 747 of file abc.py.

◆ _clientStack

list microscope.abc.DataDevice._clientStack = []
protected

Definition at line 568 of file abc.py.

◆ _dispatch_buffer

microscope.abc.DataDevice._dispatch_buffer = queue.Queue(maxsize=buffer_length)
protected

Definition at line 574 of file abc.py.

◆ _dispatch_thread [1/2]

microscope.abc.DataDevice._dispatch_thread = None
protected

Definition at line 572 of file abc.py.

◆ _dispatch_thread [2/2]

bool microscope.abc.DataDevice._dispatch_thread = True

Definition at line 624 of file abc.py.

◆ _fetch_thread [1/2]

microscope.abc.DataDevice._fetch_thread = None
protected

Definition at line 562 of file abc.py.

◆ _fetch_thread [2/2]

bool microscope.abc.DataDevice._fetch_thread = True

Definition at line 617 of file abc.py.

◆ _fetch_thread_run [1/2]

bool microscope.abc.DataDevice._fetch_thread_run = False
protected

Definition at line 564 of file abc.py.

◆ _fetch_thread_run [2/2]

None microscope.abc.DataDevice._fetch_thread_run = self._fetch_data()

Definition at line 714 of file abc.py.

◆ _liveClients

microscope.abc.DataDevice._liveClients = set()
protected

Definition at line 570 of file abc.py.

◆ _new_data

tuple microscope.abc.DataDevice._new_data = (data, timestamp)
protected

Definition at line 815 of file abc.py.

◆ _new_data_condition

microscope.abc.DataDevice._new_data_condition = threading.Condition()
protected

Definition at line 578 of file abc.py.

◆ _using_callback

bool microscope.abc.DataDevice._using_callback = False
protected

Definition at line 566 of file abc.py.

◆ enabled

bool microscope.abc.DataDevice.enabled = False

Definition at line 605 of file abc.py.

◆ set_setting

microscope.abc.DataDevice.set_setting = keep_acquiring(Device.set_setting)
static

Definition at line 585 of file abc.py.


The documentation for this class was generated from the following file: