magscope.hardware
=================

.. py:module:: magscope.hardware


Classes
-------

.. autoapisummary::

   magscope.hardware.HardwareManagerBase
   magscope.hardware.FocusMotorBase


Module Contents
---------------

.. py:class:: HardwareManagerBase

   Bases: :py:obj:`magscope.processes.ManagerProcessBase`, :py:obj:`abc.ABC`


   Abstract base class for processes in the MagScope

   Subclass requirements:
   * Each subclass should have a unique name.
   * There should only be one instance of each subclass (singleton).
   * The class name is used for consistent inter-process identification.


   .. py:attribute:: buffer_shape
      :value: (1000, 2)



   .. py:attribute:: _buffer
      :type:  magscope.datatypes.MatrixBuffer | None
      :value: None



   .. py:attribute:: _is_connected
      :type:  bool
      :value: False



   .. py:method:: setup()


   .. py:method:: do_main_loop()


   .. py:method:: quit()

      Shutdown the process (and ask the other processes to quit too).



   .. py:method:: connect()
      :abstractmethod:



   .. py:method:: disconnect()
      :abstractmethod:



   .. py:method:: fetch()
      :abstractmethod:


      Checks if the hardware has new data.

      If the hardware has new data, then it stores the
      data and timestamp in the matrix buffer (self._buffer).

      The timestamp should be the seconds since the unix epoch:
      (January 1, 1970, 00:00:00 UTC)



   .. py:method:: _save_pending_data_if_enabled() -> None


   .. py:method:: _hardware_save_filepath() -> pathlib.Path


   .. py:method:: _hardware_save_header() -> str


.. py:class:: FocusMotorBase

   Bases: :py:obj:`HardwareManagerBase`, :py:obj:`abc.ABC`


   Base class for absolute-Z focus motors used by MagScope.

   Subclasses provide the device-specific motion primitives while this base
   class standardizes polling, telemetry buffering, and the optional bridge to
   the simulated camera. The hardware matrix buffer stores rows as
   ``[timestamp, current_z, target_z, is_at_target]`` where ``is_at_target``
   is encoded as ``0.0`` or ``1.0``.


   .. py:attribute:: at_target_tolerance
      :value: 10



   .. py:attribute:: buffer_shape
      :value: (100000, 4)



   .. py:attribute:: fetch_interval
      :value: 0.05



   .. py:attribute:: _target_z
      :value: 0.0



   .. py:attribute:: _last_written
      :value: 0.0



   .. py:attribute:: _last_sent_focus
      :type:  float | None
      :value: None



   .. py:attribute:: _last_state
      :type:  tuple[float, float, bool] | None
      :value: None



   .. py:method:: setup()


   .. py:method:: fetch()

      Checks if the hardware has new data.

      If the hardware has new data, then it stores the
      data and timestamp in the matrix buffer (self._buffer).

      The timestamp should be the seconds since the unix epoch:
      (January 1, 1970, 00:00:00 UTC)



   .. py:method:: handle_move_absolute(z: float)


   .. py:method:: report_focus_motor_limits() -> None


   .. py:method:: get_target_z() -> float


   .. py:method:: is_at_target(tolerance: float | None = None) -> bool


   .. py:method:: _write_state(timestamp: float, current_z: float, *, force: bool = False) -> None


   .. py:method:: _poll_hardware(now: float) -> None

      Allow subclasses to advance device state before telemetry is sampled.



   .. py:method:: _update_simulated_camera_focus(current_z: float, *, force: bool = False) -> None


   .. py:method:: move_absolute(z: float) -> None
      :abstractmethod:


      Command the motor to move to an absolute Z position.



   .. py:method:: get_current_z() -> float
      :abstractmethod:


      Return the motor's reported current Z position.



   .. py:method:: get_is_moving() -> bool
      :abstractmethod:


      Return the motor's reported moving state.



   .. py:method:: get_position_limits() -> tuple[float, float]
      :abstractmethod:


      Return the allowed absolute Z limits for this motor.



