Skip to content

Commit cc1efa3

Browse files
Add error handling to Cryomech PTC drivers and agent acq process (#767)
* Implement error handling in Cryomech drivers * Handle ConnectionError in main acq process * Handle connection error in init task * Handle condition where socket returns None This happens when we try to reset the connection, but can't establish anything due to the device not accepting connections.
1 parent d63da56 commit cc1efa3

File tree

2 files changed

+94
-9
lines changed

2 files changed

+94
-9
lines changed

socs/agents/cryomech_cpa/agent.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ def init(self, session, params=None):
7272
fake_errors=self.fake_errors)
7373

7474
# Test connection and display identifying info
75-
self.ptc.get_data()
75+
try:
76+
self.ptc.get_data()
77+
except ConnectionError:
78+
self.log.error("Could not establish connection to compressor.")
79+
return False, "PTC agent initialization failed"
7680
print("PTC Model:", self.ptc.model)
7781
print("PTC Serial Number:", self.ptc.serial)
7882
print("Software Revision is:", self.ptc.software_revision)
@@ -141,7 +145,16 @@ def acq(self, session, params):
141145
# Publish data, waiting 1/f_sample seconds in between calls.
142146
pub_data = {'timestamp': time.time(),
143147
'block_name': 'ptc_status'}
144-
data_flag, data = self.ptc.get_data()
148+
try:
149+
data_flag, data = self.ptc.get_data()
150+
if session.degraded:
151+
self.log.info("Connection re-established.")
152+
session.degraded = False
153+
except ConnectionError:
154+
self.log.error("Failed to get data from compressor. Check network connection.")
155+
session.degraded = True
156+
time.sleep(1)
157+
continue
145158
pub_data['data'] = data
146159
# If there is an error in compressor output (data_flag = True),
147160
# do not publish

socs/agents/cryomech_cpa/drivers.py

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import random
2+
import selectors
23
import socket
34
import struct
45

@@ -16,24 +17,95 @@
1617

1718
class PTC:
1819
def __init__(self, ip_address, port=502, timeout=10, fake_errors=False):
19-
self.ip_address = ip_address
20-
self.port = int(port)
2120
self.fake_errors = fake_errors
2221

2322
self.model = None
2423
self.serial = None
2524
self.software_revision = None
2625

27-
self.comm = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
28-
self.comm.connect((self.ip_address, self.port)) # connects to the PTC
29-
self.comm.settimeout(timeout)
26+
self.ip_address = ip_address
27+
self.port = int(port)
28+
self.timeout = timeout
29+
self.comm = self._connect((self.ip_address, self.port))
30+
31+
def _connect(self, address):
32+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
33+
sock.settimeout(self.timeout)
34+
try:
35+
sock.connect(address)
36+
except TimeoutError:
37+
print(f"Connection not established within {self.timeout}.")
38+
return
39+
except OSError as e:
40+
print(f"Unable to connect. {e}")
41+
return
42+
except Exception as e:
43+
print(f"Caught unexpected {type(e).__name__} while connecting:")
44+
print(f" {e}")
45+
return
46+
return sock
47+
48+
def reset(self):
49+
print("Resetting the connection to the compressor.")
50+
self.comm = self._connect((self.ip_address, self.port))
51+
52+
def _write(self, msg):
53+
if self.comm is None:
54+
print("Connection not established. Unable to send command.")
55+
self.reset()
56+
return
57+
58+
try:
59+
self.comm.sendall(msg)
60+
return
61+
except (BrokenPipeError, ConnectionResetError) as e:
62+
print(f"Connection error: {e}")
63+
self.reset()
64+
except TimeoutError as e:
65+
print(f"Timeout error while writing: {e}")
66+
self.reset()
67+
except Exception as e:
68+
print(f"Caught unexpected {type(e).__name__} during write:")
69+
print(f" {e}")
70+
self.reset()
71+
72+
# Try a second time before giving up
73+
try:
74+
self.comm.sendall(msg)
75+
except (BrokenPipeError, ConnectionResetError) as e:
76+
print(f"Connection error: {e}")
77+
raise ConnectionError
78+
except TimeoutError as e:
79+
print(f"Timeout error while writing: {e}")
80+
raise ConnectionError
81+
except AttributeError:
82+
raise ConnectionError("Unable to reset connection.")
83+
except Exception as e:
84+
print(f"Caught unexpected {type(e).__name__} during write:")
85+
print(f" {e}")
86+
raise ConnectionError
87+
88+
def _check_ready(self):
89+
"""Check socket is ready to read from."""
90+
if self.comm is None:
91+
raise ConnectionError("Connection not established, not ready to read.")
92+
93+
sel = selectors.DefaultSelector()
94+
sel.register(self.comm, selectors.EVENT_READ)
95+
if not sel.select(self.timeout):
96+
raise ConnectionError
97+
98+
def _read(self):
99+
self._check_ready()
100+
data = self.comm.recv(1024)
101+
return data
30102

31103
def get_data(self):
32104
"""
33105
Gets the raw data from the ptc and returns it in a usable format.
34106
"""
35-
self.comm.sendall(self.buildRegistersQuery())
36-
data = self.comm.recv(1024)
107+
self._write(self.buildRegistersQuery())
108+
data = self._read()
37109
data_flag, brd = self.breakdownReplyData(data)
38110

39111
return data_flag, brd

0 commit comments

Comments
 (0)