forked from zietzm/Helmholtz_Test_Bench
Rewrite: Finished initial backend code. Connection to other components missing.
This commit is contained in:
@@ -29,6 +29,12 @@ class HelmholtzCageDevice:
|
||||
# Indicates all the threads should be joined
|
||||
self._stop_flag = Event()
|
||||
|
||||
# --- POLLING SUBSCRIBERS ---
|
||||
# This is a list of object callbacks interested in receiving device status updates.
|
||||
# This will primarily include the front-end which wants to update its display data.
|
||||
# The callback functions should accept a dict as an argument of the form {'arduino':, 'axes':[{}, {}, {}]}
|
||||
self._subscribers = []
|
||||
|
||||
# --- COMMAND QUEUEING ---
|
||||
self.command_lock = RLock()
|
||||
# Indicates to the command executing thread that a new command has arrived for execution
|
||||
@@ -94,7 +100,7 @@ class HelmholtzCageDevice:
|
||||
# Loop over axes
|
||||
for i in range(3):
|
||||
axis_dict = {}
|
||||
for key in ["coil_const", "ambient_field", "resistance", "max_volts", "max_amps"]
|
||||
for key in ["coil_const", "ambient_field", "resistance", "max_volts", "max_amps"]:
|
||||
axis_dict[key] = float(config.read_from_config(g.AXIS_NAMES[i], key, config.CONFIG_OBJECT))
|
||||
self.axes.append(axis_dict)
|
||||
|
||||
@@ -125,6 +131,11 @@ class HelmholtzCageDevice:
|
||||
self.proxy_id = None
|
||||
# Otherwise do nothing, this case requires no behaviour
|
||||
|
||||
def subscribe_status_updates(self, callback):
|
||||
# List containing all interested subscribers.
|
||||
# We won't check if a callback is added twice. Not our responsibility
|
||||
self._subscribers.append(callback)
|
||||
|
||||
def queue_command(self, proxy_obj, command):
|
||||
""" Queues a dict for immediate execution containing the command for the cage as a whole.
|
||||
Since the newest command should always be run, it is not a real queue (just a variable)"""
|
||||
@@ -172,8 +183,19 @@ class HelmholtzCageDevice:
|
||||
if stop_flag_set:
|
||||
return
|
||||
|
||||
status_data = {'axes': []}
|
||||
with self.hardware_lock:
|
||||
pass
|
||||
# This polls all three axes at once
|
||||
for i in range(3):
|
||||
# Helper function to find correct psu and channel to talk to
|
||||
psu, channel = self._get_psu_for_axis(i)
|
||||
# This is a slow operation, watch out!
|
||||
status = psu.poll_channel_state(channel)
|
||||
status_data['axes'].append(status)
|
||||
|
||||
# Distribute status data to all interested subscribers
|
||||
for subscriber in self._subscribers:
|
||||
subscriber(status_data)
|
||||
|
||||
def _set_field_raw(self, arg):
|
||||
currents = []
|
||||
@@ -217,33 +239,40 @@ class HelmholtzCageDevice:
|
||||
# min. 8V, max. max_volts, in-between as needed with current value (+margin to not limit current)
|
||||
voltage_limit = min(max(1.3 * abs(safe_current) * self.axes[i]['resistance'], 8),
|
||||
self.axes[i]['max_volts']) # limit voltage
|
||||
# TODO: This kind of stuff belongs in the config and should not be hardcoded
|
||||
# Determine which channel of which psu is required
|
||||
if i == 0 or i == 1:
|
||||
psu = self.psu1
|
||||
channel = psu.valid_channels[i]
|
||||
else:
|
||||
psu = self.psu2
|
||||
channel = psu.valid_channels[0]
|
||||
|
||||
# Helper function to find correct psu and channel to talk to
|
||||
psu, channel = self._get_psu_for_axis(i)
|
||||
|
||||
# Set voltages and currents. Outputs should already be active from initializer.
|
||||
psu.set_current(channel, safe_current)
|
||||
psu.set_voltage(channel, voltage_limit)
|
||||
|
||||
def _get_psu_for_axis(self, axis_index):
|
||||
"""Determine which channel of which psu is required"""
|
||||
# TODO: This kind of stuff belongs in the config and should not be hardcoded
|
||||
if axis_index == 0 or axis_index == 1:
|
||||
psu = self.psu1
|
||||
channel = psu.valid_channels[axis_index]
|
||||
else:
|
||||
psu = self.psu2
|
||||
channel = psu.valid_channels[0]
|
||||
return psu, channel
|
||||
|
||||
def shutdown(self):
|
||||
""" Shuts down the hardware. This special command overrides the currently active proxy.
|
||||
The object cannot be recovered from this state, but may be re-instantiated."""
|
||||
|
||||
# Send signals to kill threads:
|
||||
# TODO: Handle timeout behaviour
|
||||
self._stop_flag.set()
|
||||
# _cmd_exec_thread:
|
||||
with self.command_lock:
|
||||
self.command = None
|
||||
self.new_command_flag.set() # Causes the thread to unblock
|
||||
self._cmd_exec_thread.join(timeout=2)
|
||||
# TODO: Handle timeout behaviour
|
||||
#_hw_poll_thread:
|
||||
|
||||
# This thread is stopped just by setting the _stop_flag
|
||||
self._hw_poll_thread.join(timeout=2)
|
||||
|
||||
# This waiting period is not easily removed without resulting in unexpected behaviour
|
||||
with self.hardware_lock:
|
||||
|
||||
Reference in New Issue
Block a user