@@ -70,6 +70,32 @@ async def raise_if_error(self, raise_from: Exception):
7070 raise RobotLoadError (int (error_code ), error_string ) from raise_from
7171
7272
73+ # Error codes that we do special things on
74+ class ProgErrorCode (IntEnum ):
75+ NO_ERROR = 0
76+ SAMPLE_POSITION_NOT_READY = 9
77+ NO_PIN_ERROR_CODE = 25
78+
79+ @classmethod
80+ def is_retryable (cls , error_code : int ) -> bool :
81+ return error_code in {
82+ ProgErrorCode .NO_ERROR ,
83+ ProgErrorCode .SAMPLE_POSITION_NOT_READY ,
84+ }
85+
86+
87+ class ControllerErrorCode (IntEnum ):
88+ NO_ERROR = 0
89+ LIGHT_CURTAIN_TRIPPED = 40
90+
91+ @classmethod
92+ def is_retryable (cls , error_code : int ) -> bool :
93+ return error_code in {
94+ ControllerErrorCode .NO_ERROR ,
95+ ControllerErrorCode .LIGHT_CURTAIN_TRIPPED ,
96+ }
97+
98+
7399class BartRobot (StandardReadable , Movable [SampleLocation ]):
74100 """The sample changing robot."""
75101
@@ -79,11 +105,6 @@ class BartRobot(StandardReadable, Movable[SampleLocation]):
79105 # How long to wait for the actual load to happen
80106 LOAD_TIMEOUT = 60
81107
82- # Error codes that we do special things on
83- NO_ERROR = 0
84- NO_PIN_ERROR_CODE = 25
85- LIGHT_CURTAIN_TRIPPED = 40
86-
87108 # How far the gonio position can be out before loading will fail
88109 LOAD_TOLERANCE_MM = 0.02
89110
@@ -138,19 +159,32 @@ async def beamline_status_or_error(self, expected_state: BeamlineStatus):
138159 there is an error a RobotLoadError error is raised.
139160 """
140161
141- async def raise_if_error ():
162+ async def raise_if_prog_error ():
142163 await wait_for_value (
143- self .prog_error .code , lambda value : value != self .NO_ERROR , None
164+ self .prog_error .code ,
165+ lambda value : value != ProgErrorCode .NO_ERROR ,
166+ None ,
144167 )
145168 error_code = await self .prog_error .code .get_value ()
146169 error_msg = await self .prog_error .str .get_value ()
147170 raise RobotLoadError (error_code , error_msg )
148171
172+ async def raise_if_ctl_error ():
173+ await wait_for_value (
174+ self .controller_error .code ,
175+ lambda value : value != ControllerErrorCode .NO_ERROR ,
176+ None ,
177+ )
178+ error_code = await self .controller_error .code .get_value ()
179+ error_msg = await self .controller_error .str .get_value ()
180+ raise RobotLoadError (error_code , error_msg )
181+
149182 async def wait_for_expected_state ():
150183 await wait_for_value (self .beamline_disabled , expected_state .value , None )
151184
152185 tasks = [
153- (Task (raise_if_error ())),
186+ (Task (raise_if_prog_error ())),
187+ (Task (raise_if_ctl_error ())),
154188 (Task (wait_for_expected_state ())),
155189 ]
156190 try :
@@ -170,10 +204,32 @@ async def wait_for_expected_state():
170204
171205 raise
172206
173- async def _load_pin_and_puck (self , sample_location : SampleLocation ):
174- if await self .controller_error .code .get_value () == self .LIGHT_CURTAIN_TRIPPED :
175- LOGGER .info ("Light curtain tripped, trying again" )
207+ async def _check_errors_and_clear_if_retryable (self ):
208+ ctl_err_code = await self .controller_error .code .get_value ()
209+ prog_err_code = await self .prog_error .code .get_value ()
210+ if (
211+ ctl_err_code != ControllerErrorCode .NO_ERROR
212+ or prog_err_code != ProgErrorCode .NO_ERROR
213+ ):
214+ ctl_err_msg = await self .controller_error .str .get_value ()
215+ prog_err_msg = await self .prog_error .str .get_value ()
216+ if ctl_err_code != ControllerErrorCode .NO_ERROR :
217+ LOGGER .info (
218+ f"Detected error from previous load/unload attempt controller_error { ctl_err_code } :{ ctl_err_msg } "
219+ )
220+ if prog_err_code != ProgErrorCode .NO_ERROR :
221+ LOGGER .info (
222+ f"Detected error from previous load/unload attempt prog_error { prog_err_code } :{ prog_err_msg } "
223+ )
224+ if not ProgErrorCode .is_retryable (prog_err_code ):
225+ raise RobotLoadError (prog_err_code , prog_err_msg )
226+ if not ControllerErrorCode .is_retryable (ctl_err_code ):
227+ raise RobotLoadError (ctl_err_code , ctl_err_msg )
228+
229+ LOGGER .info ("Errors are retryable, resetting errors and trying again" )
176230 await self .reset .trigger ()
231+
232+ async def _load_pin_and_puck (self , sample_location : SampleLocation ):
177233 LOGGER .info (f"Loading pin { sample_location } " )
178234 if await self .program_running .get_value ():
179235 LOGGER .info (
@@ -210,6 +266,7 @@ async def set(self, value: SampleLocation):
210266 sample.
211267 """
212268 try :
269+ await self ._check_errors_and_clear_if_retryable ()
213270 if value != SAMPLE_LOCATION_EMPTY :
214271 await wait_for (
215272 self ._load_pin_and_puck (value ),
0 commit comments