Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions sentio_prober_control/Sentio/CommandGroups/ProbeCommandGroup.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from typing import Tuple

from sentio_prober_control.Sentio.Enumerations import ProbePosition, XyReference, ZReference, ChuckSite
from sentio_prober_control.Sentio.Enumerations import ProbePosition, XyReference, ZReference, ChuckSite, Stage
from sentio_prober_control.Sentio.Response import Response
from sentio_prober_control.Sentio.CommandGroups.CommandGroupBase import CommandGroupBase
from sentio_prober_control.Sentio.Compatibility import Compatibility, CompatibilityLevel
from sentio_prober_control.Sentio.CommandGroups.StageCommandGroup import StageCommandGroup


class ProbeCommandGroup(CommandGroupBase):
"""This command group contains functions for working with motorized prober.
Expand All @@ -20,9 +22,37 @@ class ProbeCommandGroup(CommandGroupBase):
```
"""

class _TopBottomPositionSelector:
""" This is a dummy command group for providing access to top and bottom probes.
"""
def __init__(self, prober: 'SentioProber', stage : Stage, stage_selector : str) -> None: # type: ignore
self.east : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:east")
self.west : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:west")
self.north : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:north")
self.south : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:south")
self.northeast : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:northeast")
self.northwest : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:northwest")
self.southeast : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:southeast")
self.southwest : StageCommandGroup = StageCommandGroup(prober, stage, f"{stage_selector}:southwest")


def __init__(self, prober: 'SentioProber') -> None:
super().__init__(prober)

if Compatibility.level >= CompatibilityLevel.Sentio_25_2:
self.top = self._TopBottomPositionSelector(prober, Stage.TopProbe, "probe:top")
self.bottom = self._TopBottomPositionSelector(prober, Stage.BottomProbe, "probe:bottom")

# Top probes are also available as east, west, north, south, northeast, northwest, southeast, southwest
self.east = self.top.east
self.west = self.top.west
self.north = self.top.north
self.south = self.top.south
self.northeast = self.top.northeast
self.northwest = self.top.northwest
self.southeast = self.top.southeast
self.southwest = self.top.southwest


def async_step_probe_site(self, probe: ProbePosition, idx: int) -> int:
"""Start the process of stepping to a positioner site.
Expand Down Expand Up @@ -265,9 +295,11 @@ def set_probe_home(self, probe: ProbePosition, site: ChuckSite | None = None, x:
"""
if site is None:
self.comm.send(f"set_positioner_home {probe.to_string()}")
else:
elif x is not None and y is not None:
self.comm.send(f"set_positioner_home {probe.to_string()},{site.to_string()},{x},{y}")

else:
raise ValueError("When site is specified, x and y must also be specified.")

Response.check_resp(self.comm.read_line())


Expand Down Expand Up @@ -352,7 +384,7 @@ def get_probe_status(self, probe: ProbePosition) -> str:

Returns:
Status of positioner with 4 digits, 1st digit indicates the East Positioner, 2nd digit indicates West Positioner
3rd digit indicates the North Positioner, 4rd digit indicates the South Positioner.
3rd digit indicates the North Positioner, 4th digit indicates the South Positioner.
"""

self.comm.send(f"get_positioner_status {probe.to_string()}")
Expand Down
34 changes: 34 additions & 0 deletions sentio_prober_control/Sentio/CommandGroups/ScopeCommandGroup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

from typing import Optional


from sentio_prober_control.Sentio.CommandGroups.StageCommandGroup import StageCommandGroup
from sentio_prober_control.Sentio.Compatibility import CompatibilityLevel, Compatibility
from sentio_prober_control.Sentio.Enumerations import Stage





class ScopeCommandGroup(StageCommandGroup):
"""This command group contains functions for working with motorized scopes.
You are not meant to instantiate this class directly. Access it via the probe attribute
of the [SentioProber](SentioProber.md) class.

Example:

```py
from sentio_prober_control.Sentio.ProberSentio import SentioProber

prober = SentioProber.create_prober("tcpip", "127.0.0.1:35555")
prober.scope.move_probe_xy(XyReference.Current, 1000, 2000)
```
"""

def __init__(self, prober: 'SentioProber', stage : Stage, stage_selector : str) -> None: # type: ignore
super().__init__(prober, stage, stage_selector)

if Compatibility.level >= CompatibilityLevel.Sentio_25_2:
self.top : StageCommandGroup = StageCommandGroup(self, Stage.Scope, "scope:top")
self.bottom : StageCommandGroup = StageCommandGroup(self, Stage.BottomScope, "scope:bottom")
self.aux : StageCommandGroup = StageCommandGroup(self, Stage.AuxiliaryScope, "scope:aux")
29 changes: 9 additions & 20 deletions sentio_prober_control/Sentio/CommandGroups/StageCommandGroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

from typing import Optional


class StageCommandGroup(CommandGroupBase):
"""This command group contains functions for working with motorized scopes.
"""This command group contains functions for working with motorized stages.
You are not meant to instantiate this class directly. Access it via the probe attribute
of the [SentioProber](SentioProber.md) class.

Expand All @@ -21,27 +22,11 @@ class StageCommandGroup(CommandGroupBase):
```
"""

def __init__(self, prober: 'SentioProber', stage : Stage, has_subgroups = False) -> None: # type: ignore
def __init__(self, prober: 'SentioProber', stage : Stage, stage_selector : str) -> None: # type: ignore
super().__init__(prober)

self.__stage_selector: str = ""
self.__stage = stage

if stage==Stage.Scope:
self.__stage_selector = "scope:top"
elif stage==Stage.BottomScope:
self.__stage_selector = "scope:bottom"
elif stage==Stage.AuxiliaryScope:
self.__stage_selector = "scope:aux"
elif stage==Stage.Chuck:
self.__stage_selector = "chuck"
else:
raise ValueError(f"Invalid stage {stage} for ScopeCommandGroup")

if stage==Stage.Scope and has_subgroups:
self.top: StageCommandGroup = StageCommandGroup(prober, Stage.Scope, False)
self.bottom: StageCommandGroup = StageCommandGroup(prober, Stage.BottomScope, False)
self.aux: StageCommandGroup = StageCommandGroup(prober, Stage.AuxiliaryScope, False)
self.__stage_selector = stage_selector


def get_home(self, chuck_site : ChuckSite = ChuckSite.Wafer) -> Tuple[float, float, ChuckSite]:
Expand Down Expand Up @@ -257,4 +242,8 @@ def step_site_next(self) -> Tuple[str, float, float]:
@property
def stage(self) -> Stage:
"""The stage this command group is for."""
return self.__stage
return self.__stage




7 changes: 4 additions & 3 deletions sentio_prober_control/Sentio/Compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ class CompatibilityLevel(IntEnum):
It is used to determine which features are available in the prober. This enum
only contains SENTIO versions which introduces API changes.
"""
Undefined = 0,
Sentio_24 = 1,
Auto = 0
Sentio_24 = 1
Sentio_25_2 = 2
Experimental = 99


class Compatibility:
Expand All @@ -22,7 +23,7 @@ class Compatibility:
"""

# Default compatibility level is Undefined
level : CompatibilityLevel = CompatibilityLevel.Undefined
level : CompatibilityLevel = CompatibilityLevel.Auto

@staticmethod
def assert_min(level : CompatibilityLevel) -> None:
Expand Down
4 changes: 2 additions & 2 deletions sentio_prober_control/Sentio/Enumerations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2048,8 +2048,8 @@ class ZReference(Enum):
Ready = 7
RealPos = 8

def to_string(self, compat_level : CompatibilityLevel = CompatibilityLevel.Undefined) -> str:
if compat_level == CompatibilityLevel.Undefined:
def to_string(self, compat_level : CompatibilityLevel = CompatibilityLevel.Auto) -> str:
if compat_level == CompatibilityLevel.Auto:
compat_level = Compatibility.level

if compat_level < CompatibilityLevel.Sentio_25_2:
Expand Down
45 changes: 25 additions & 20 deletions sentio_prober_control/Sentio/ProberSentio.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from sentio_prober_control.Sentio.CommandGroups.WafermapCommandGroup import WafermapCommandGroup
from sentio_prober_control.Sentio.CommandGroups.SetupCommandGroup import SetupCommandGroup
from sentio_prober_control.Sentio.CommandGroups.StageCommandGroup import StageCommandGroup
from sentio_prober_control.Sentio.CommandGroups.ScopeCommandGroup import ScopeCommandGroup


class SentioCommunicationType(Enum):
Expand Down Expand Up @@ -79,22 +80,22 @@ class SentioProber(ProberBase):
vision (VisionCommandGroup): The vision command group provides access to the vision modules functionality.
"""

def __init__(self, comm: CommunicatorBase):
def __init__(self, comm: CommunicatorBase, compat_level : CompatibilityLevel = CompatibilityLevel.Auto) -> None:
"""Construct a SENTIO prober object.

The prober must be initialized with a communication object that
specifies how the system communicates with the probe station.

Args:
comm (CommunicatorBase): The communicator to use for communication with the prober.
compat_level (CompatibilityLevel): The compatibility level to use. If CompatibilityLevel.Auto is set SENTIO is queried to figure the compatibility level out.
"""
ProberBase.__init__(self, comm)

# Standard command groups
self.aux: AuxCommandGroup = AuxCommandGroup(self)
self.loader: LoaderCommandGroup = LoaderCommandGroup(self)
self.map: WafermapCommandGroup = WafermapCommandGroup(self)
self.probe: ProbeCommandGroup = ProbeCommandGroup(self)
self.qalibria: QAlibriaCommandGroup = QAlibriaCommandGroup(self)
self.service: ServiceCommandGroup = ServiceCommandGroup(self)
self.siph: SiPHCommandGroup = SiPHCommandGroup(self)
Expand All @@ -105,31 +106,35 @@ def __init__(self, comm: CommunicatorBase):
self.__name = "SentioProber"
self.comm.send("*RCS 1") # switch to the native SENTIO remote command set

version : str = self.status.get_version()

# Extract version string
match = re.search(r"Version:\s*([\d\.]+)", version)
if match:
version = match.group(1)
parts = version.split(".")
major = int(parts[0]) if len(parts) > 0 else None
minor = int(parts[1]) if len(parts) > 1 else None
release = int(parts[2]) if len(parts) > 2 else None
if major==24:
Compatibility.level = CompatibilityLevel.Sentio_24
elif major==25 and (minor==2 or (minor==1 and release==99)):
Compatibility.level = CompatibilityLevel.Sentio_25_2
else:
Compatibility.level = CompatibilityLevel.Undefined
# If the compatibility Level is set to Auto, we will try to determine the compatibility level
if compat_level == CompatibilityLevel.Auto:
version : str = self.status.get_version()

# Extract version string
match = re.search(r"Version:\s*([\d\.]+)", version)
if match:
version = match.group(1)
parts = version.split(".")
major = int(parts[0]) if len(parts) > 0 else None
minor = int(parts[1]) if len(parts) > 1 else None
release = int(parts[2]) if len(parts) > 2 else None
if major==25 and (minor==2 or (minor==1 and release==99)):
Compatibility.level = CompatibilityLevel.Sentio_25_2
else:
Compatibility.level = CompatibilityLevel.Sentio_24

#
# More command groups not supported by all SENTIO versions.
#

# The probe command group has optional sub-groups for top and bottom probes.
# These are only available for Sentio > 25.2
self.probe: ProbeCommandGroup = ProbeCommandGroup(self)

# Command groups for stages; Only available for Sentio > 25.2
if Compatibility.level >= CompatibilityLevel.Sentio_25_2:
self.scope: StageCommandGroup = StageCommandGroup(self, Stage.Scope, True)
self.chuck: StageCommandGroup = StageCommandGroup(self, Stage.Chuck, False)
self.scope: ScopeCommandGroup = ScopeCommandGroup(self, Stage.Scope, "scope:top")
self.chuck: StageCommandGroup = StageCommandGroup(self, Stage.Chuck, "chuck")

#
# Deprecated command groups
Expand Down