55
66import pexpect
77
8- from .utils import run_command
9-
108
119class CannotConnectError (Exception ):
1210 pass
@@ -78,6 +76,7 @@ def connect(self):
7876 logfile = sys .stdout ,
7977 echo = False ,
8078 codec_errors = "ignore" ,
79+ timeout = 5 ,
8180 )
8281 try :
8382 # first check for connection refusal
@@ -89,7 +88,7 @@ def connect(self):
8988 report ("Cannot connect to remote IOC, connection in use?" )
9089 raise CannotConnectError
9190
92- def check_prompt (self , retries ) -> RtemsState :
91+ def check_prompt (self , retries , timeout = 15 ) -> RtemsState :
9392 """
9493 Determine if we are currently seeing an IOC shell prompt or
9594 bootloader. Because there is a possibility that we are in the middle
@@ -104,24 +103,33 @@ def check_prompt(self, retries) -> RtemsState:
104103 self ._child .sendline (self .IOC_CHECK )
105104 self ._child .expect (self .IOC_RESPONSE , timeout = 1 )
106105 except pexpect .exceptions .TIMEOUT :
107- try :
108- # see if we are in the bootloader
109- self ._child .sendline ()
110- self ._child .expect (self .MOT_PROMPT , timeout = 1 )
111- except pexpect .exceptions .TIMEOUT :
112- # current state unknown. wait and retry
113- sleep (15 )
114- else :
115- report ("Currently in bootloader" )
116- return RtemsState .MOT
106+ pass
117107 else :
118- report ("Currently in IOC shell" )
119108 return RtemsState .IOC
120109
110+ try :
111+ # see if we are in the bootloader
112+ self ._child .sendline ()
113+ self ._child .expect (self .MOT_PROMPT , timeout = 1 )
114+ except pexpect .exceptions .TIMEOUT :
115+ pass
116+ else :
117+ return RtemsState .MOT
118+
119+ try :
120+ # current state unknown. check for mot start prompt
121+ # in case we are in a boot loop
122+ self ._child .expect (self .CONTINUE , timeout = timeout )
123+ except pexpect .exceptions .TIMEOUT :
124+ pass
125+ else :
126+ # send escape to get into the bootloader
127+ self ._child .sendline (chr (27 ))
128+ return RtemsState .MOT
129+
121130 report (f"Retry { retry + 1 } of get current status" )
122131
123- report ("Current state UNKNOWN" )
124- raise CannotConnectError ("Current state of remote IOC unknown" )
132+ return RtemsState .UNKNOWN
125133
126134 def reboot (self , into : RtemsState ):
127135 """
@@ -145,6 +153,8 @@ def reboot(self, into: RtemsState):
145153 # send space to boot the IOC
146154 self ._child .send (" " )
147155
156+ self .ioc_rebooted = True
157+
148158 def get_epics_prompt (self , retries = 5 ):
149159 """
150160 Get to the IOC shell prompt, if the IOC is not already running, reboot
@@ -153,27 +163,26 @@ def get_epics_prompt(self, retries=5):
153163 """
154164 assert self ._child , "must call connect before get_epics_prompt"
155165
156- current = self .check_prompt (retries = 10 )
166+ current = self .check_prompt (retries = retries )
157167
158168 if current != RtemsState .IOC or (self ._ioc_reboot and not self .ioc_rebooted ):
159169 sleep (0.5 )
160- report ("Rebooting the IOC" )
161170
171+ report ("Rebooting into IOC shell" )
162172 self .reboot (RtemsState .IOC )
163- self .ioc_rebooted = True
164173
165- current = self .check_prompt (retries = 10 )
174+ current = self .check_prompt (retries = retries )
166175 if current != RtemsState .IOC :
167176 raise CannotConnectError ("Failed to reboot into IOC shell" )
168177
169- def get_boot_prompt (self ):
178+ def get_boot_prompt (self , retries = 5 ):
170179 """
171180 Get to the bootloader prompt, if the IOC shell is running then exit
172181 and send appropriate commands to get to the bootloader
173182 """
174183 assert self ._child , "must call connect before get_boot_prompt"
175184
176- current = self .check_prompt (retries = 10 )
185+ current = self .check_prompt (retries = retries )
177186 if current != RtemsState .MOT :
178187 # get out of the IOC and return to MOT
179188 self .reboot (RtemsState .MOT )
@@ -185,8 +194,9 @@ def sendline(self, command: str) -> None:
185194 """
186195 Send a command to the telnet session
187196 """
197+ # always pause a little to allow the previous expect to complete
188198 assert self ._child , "must call connect before send"
189- self ._child .sendline (command )
199+ self ._child .sendline (command + " \r " )
190200
191201 def expect (self , pattern , timeout = 10 ) -> None :
192202 """
@@ -221,70 +231,3 @@ def report(message):
221231 print a message that is noticeable amongst all the other output
222232 """
223233 print (f"\n >>>> { message } <<<<\n " )
224-
225-
226- def ioc_connect (
227- host_and_port : str ,
228- reboot : bool = False ,
229- attach : bool = True ,
230- raise_errors : bool = False ,
231- ):
232- """
233- Entrypoint to make a connection to an RTEMS IOC over telnet.
234- Once connected, enters an interactive user session with the IOC.
235-
236- args:
237- host_and_port: 'hostname:port' of the IOC to connect to
238- reboot: reboot the IOC to pick up new binaries/startup/epics db
239- """
240- telnet = TelnetRTEMS (host_and_port , reboot )
241-
242- try :
243- telnet .connect ()
244-
245- # this will untangle a partially executed gevEdit command
246- for _ in range (3 ):
247- telnet .sendline ("\r " )
248-
249- if reboot :
250- telnet .get_epics_prompt (retries = 10 )
251- else :
252- report ("Auto reboot disabled. Skipping reboot" )
253-
254- except (CannotConnectError , pexpect .exceptions .TIMEOUT ):
255- report ("Connection failed, Exiting." )
256- telnet .close ()
257- raise
258-
259- except Exception as e :
260- # flush any remaining buffered output to stdout
261- telnet .flush_remaining_output ()
262- report (f"An error occurred: { e } " )
263- telnet .close ()
264- if raise_errors :
265- raise
266-
267- telnet .close ()
268- if attach :
269- report ("Connecting to IOC console, hit enter for a prompt" )
270- run_command (telnet .command )
271-
272-
273- def motboot_connect (
274- host_and_port : str , reboot : bool = False , use_console : bool = False
275- ) -> TelnetRTEMS :
276- """
277- Connect to the MOTBoot bootloader prompt, rebooting if needed.
278-
279- Returns a TelnetRTEMS object that is connected to the MOTBoot bootloader
280- """
281- telnet = TelnetRTEMS (host_and_port , ioc_reboot = reboot , use_console = use_console )
282- telnet .connect ()
283-
284- # this will untangle a partially executed gevEdit command
285- for _ in range (3 ):
286- telnet .sendline ("\r " )
287-
288- telnet .get_boot_prompt ()
289-
290- return telnet
0 commit comments