Skip to content

Commit

Permalink
Making initial round of changes based on responses to PR #715
Browse files Browse the repository at this point in the history
  • Loading branch information
texmexlab committed Aug 25, 2024
1 parent 4617ee6 commit fa297e7
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 56 deletions.
11 changes: 0 additions & 11 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,3 @@ pyModbusTCP

# Contributing
pre-commit

# Ensure compatability with Setuptools 71
packaging>=24
ordered-set>=3.1.1
more_itertools>=8.8
jaraco.text>=3.7
importlib_resources>=5.10.2
importlib_metadata>=6
tomli>=2.0.1
wheel>=0.43.0
platformdirs>=2.6.2
120 changes: 89 additions & 31 deletions socs/agents/scpi_psu/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,24 @@


class ScpiPsuAgent:
def __init__(self, agent, ip_address, gpib_slot, **kwargs):
def __init__(self, agent, ip_address, gpib_slot=None, port=None):
self.agent = agent
self.log = agent.log
self.lock = TimeoutLock()

self.job = None
self.ip_address = ip_address
self.gpib_slot = gpib_slot
self.gpib_slot = None
self.port = None
if ('port' in kwargs.keys()):
self.port = kwargs['port']
self.monitor = False

self.psu = None

if gpib_slot is not None:
self.gpib_slot = gpib_slot
if port is not None:
self.port = port

# Registers Temperature and Voltage feeds
agg_params = {
'frame_length': 10 * 60,
Expand All @@ -33,7 +36,7 @@ def __init__(self, agent, ip_address, gpib_slot, **kwargs):
agg_params=agg_params,
buffer_time=0)

# @ocs_agent.param('_')
@ocs_agent.param('auto_acquire', default=False, type=bool)
def init(self, session, params=None):
"""init()
Expand All @@ -44,7 +47,10 @@ def init(self, session, params=None):
if not acquired:
return False, "Could not acquire lock"

if self.port is None: # Use the old Prologix-based GPIB code
if self.gpib_slot is None and self.port is None:
self.log.error('Either --gpib-slot or --port must be specified')
return False, "Parameter not set"
elif self.port is None: # Use the old Prologix-based GPIB code
try:
self.psu = PsuInterface(self.ip_address, self.gpib_slot)
self.idn = self.psu.identify()
Expand All @@ -53,17 +59,20 @@ def init(self, session, params=None):
return False, "Timeout"
else: # Use the new direct ethernet connection code
try:
self.psu = ScpiPsuInterface(self.ip_address, self.gpib_slot, port=self.port)
self.psu = ScpiPsuInterface(self.ip_address, port=self.port)
self.idn = self.psu.identify()
except socket.timeout as e:
self.log.error(f"PSU timed out during connect: {e}")
return False, "Timeout"
except ValueError as e:
if (e.args[0].startswith('Model number')):
self.log.error(f"PSU initialization error: {e}. Suggest appending {e.args[-1]} to the list of known model numbers in scpi_psu/drivers.py")
self.log.warn(f"PSU initialization: {e}. \
Number of channels defaults to 3. \
Suggest appending {e.args[-1]} to the list \
of known model numbers in scpi_psu/drivers.py")
else:
self.log.error(f"PSU initialization resulted in unknown ValueError: {e}")
return False, "ValueError"
return False, "ValueError"

self.log.info("Connected to psu: {}".format(self.idn))

Expand All @@ -72,7 +81,7 @@ def init(self, session, params=None):

if auto_acquire:
acq_params = None
if self.psu.numChannels == 1:
if self.psu.num_channels == 1:
acq_params = {'channels': [1]}
self.agent.start('monitor_output', acq_params)
return True, 'Initialized PSU.'
Expand All @@ -94,7 +103,6 @@ def monitor_output(self, session, params=None):
Defaults to False.
"""
session.set_status('running')
self.monitor = True

while self.monitor:
Expand Down Expand Up @@ -145,18 +153,33 @@ def get_voltage(self, session, params=None):
Parameters:
channel (int): Channel number (1, 2, or 3).
Examples:
Example for calling in a client::
client.get_voltage(channel=1)
Notes:
An example of the session data::
>>> response.session['data']
{'timestamp': 1723671503.4899583,
'channel': 1,
'voltage': 0.0512836}
"""
chan = params['channel']
with self.lock.acquire_timeout(1) as acquired:
if acquired:
data = {
'timestamp': time.time(),
'block_name': 'output',
'data': {}
}

data['data']['Voltage_{}'.format(chan)] = self.psu.get_volt(chan)
session.data = data
if self.psu.get_output(chan):
data = {
'timestamp': time.time(),
'channel': chan,
'voltage': self.psu.get_volt(chan)
}

session.data = data
else:
return False, "Cannot measure output when output is disabled."
else:
return False, "Could not acquire lock"
return True, 'Channel {} voltage measured'.format(chan)
Expand Down Expand Up @@ -191,17 +214,33 @@ def get_current(self, session, params=None):
Parameters:
channel (int): Channel number (1, 2, or 3).
Examples:
Example for calling in a client::
client.get_current(channel=1)
Notes:
An example of the session data::
>>> response.session['data']
{'timestamp': 1723671503.4899583,
'channel' : 1,
'current': 0.0103236}
"""
chan = params['channel']
with self.lock.acquire_timeout(1) as acquired:
if acquired:
data = {
'timestamp': time.time(),
'block_name': 'output',
'data': {}
}
data['data']['Current_{}'.format(chan)] = self.psu.get_curr(chan)
session.data = data
# Check if output is enabled before measuring
if self.psu.get_output(chan):
data = {
'timestamp': time.time(),
'channel': chan,
'current': self.psu.get_curr(chan)
}
session.data = data
else:
return False, "Cannot measure output when output is disabled."
else:
return False, "Could not acquire lock"
return True, 'Channel {} current measured'.format(chan)
Expand Down Expand Up @@ -233,18 +272,38 @@ def get_output(self, session, params=None):
**Task** - Check if channel ouput is enabled or disabled.
Parameters:
channel (int):
channel (int): Channel number (1, 2, or 3).
Examples:
Example for calling in a client::
client.get_output(channel=1)
Notes:
An example of the session data::
>>> response.session['data']
{'timestamp': 1723671503.4899583,
'channel_1': 'enabled'}
"""
chan = params['channel']
enabled = False
data = {}
with self.lock.acquire_timeout(1) as acquired:
if acquired:
enabled = self.psu.get_output(params['channel'])
data['timestamp'] = time.time()
enabled = self.psu.get_output(chan)
else:
return False, "Could not acquire lock."
if enabled:
return True, 'Channel {} output is currently enabled.'.format(params['channel'])
data['channel_{}'.format(chan)] = 'enabled'
session.data = data
return True, 'Channel {} output is currently enabled.'.format(chan)
else:
return True, 'Channel {} output is currently disabled.'.format(params['channel'])
data['channel_{}'.format(chan)] = 'disabled'
session.data = data
return True, 'Channel {} output is currently disabled.'.format(chan)

@ocs_agent.param('channel', type=int, choices=[1, 2, 3])
@ocs_agent.param('state', type=bool)
Expand Down Expand Up @@ -304,7 +363,6 @@ def main(args=None):
agent.register_task('set_current', p.set_current)
agent.register_task('set_output', p.set_output)

# Need tasks for get_voltage, get_current, and get_output
agent.register_task('get_voltage', p.get_voltage)
agent.register_task('get_current', p.get_current)
agent.register_task('get_output', p.get_output)
Expand Down
35 changes: 21 additions & 14 deletions socs/agents/scpi_psu/drivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@
from socs.common.prologix_interface import PrologixInterface

# append new model strings as needed
ONE_CHANNEL_MODELS = ['2280S-60-3', '2280S-32-6']
ONE_CHANNEL_MODELS = ['2280S-60-3', '2280S-32-6', '9171',
'9172', '9181', '9182', '9183', '9184', '9185']
TWO_CHANNEL_MODELS = ['9173', '9174']
THREE_CHANNEL_MODELS = ['2230G-30-1']
UNDEFINED_HEADER = -113
HEADER_SUFFIX_OUT_OF_RANGE = -114


class ScpiPsuInterface:
def __init__(self, ip_address, gpibAddr, port, **kwargs):
def __init__(self, ip_address, port, **kwargs):
self.ip_address = ip_address
self.gpibAddr = gpibAddr
self.port = port
self.sock = None
self.model = None
self.numChannels = 0
self.num_channels = 0
self.conn_socket()
try:
self.configure()
Expand Down Expand Up @@ -51,11 +54,15 @@ def read_model(self):

def configure(self):
self.model = self.read_model()

if (self.model in ONE_CHANNEL_MODELS):
self.numChannels = 1
self.num_channels = 1
if (self.model in TWO_CHANNEL_MODELS):
self.num_channels = 2
if (self.model in THREE_CHANNEL_MODELS):
self.numChannels = 3
if (self.numChannels == 0):
self.num_channels = 3
if (self.num_channels == 0):
self.num_channels = 3
raise ValueError('Model number not found in known device models', self.model)

def enable(self, ch):
Expand All @@ -64,9 +71,9 @@ def enable(self, ch):
Depending on state of power supply, it might need to be called
before the output is set.
'''
if (self.numChannels != 1):
if (self.num_channels != 1):
self.set_chan(ch)
self.write('OUTP:ENAB ON')
self.write('OUTP:ENAB ON')

def disable(self, ch):
'''
Expand All @@ -76,7 +83,7 @@ def disable(self, ch):
self.write('OUTP:ENAB OFF')

def set_chan(self, ch):
if (self.numChannels != 1):
if (self.num_channels != 1):
self.write('inst:nsel ' + str(ch))

def set_output(self, ch, out):
Expand All @@ -92,7 +99,7 @@ def set_output(self, ch, out):
'''
self.set_chan(ch)
self.enable(ch)
if (self.numChannels != 1):
if (self.num_channels != 1):
if isinstance(out, str):
self.write('CHAN:OUTP ' + out)
elif out:
Expand All @@ -112,7 +119,7 @@ def get_output(self, ch):
check if the output of a channel (1,2,3) is on (True) or off (False)
'''
self.set_chan(ch)
if (self.numChannels != 1):
if (self.num_channels != 1):
self.write('CHAN:OUTP:STAT?')
else:
self.write('OUTP:STAT?')
Expand All @@ -129,7 +136,7 @@ def set_curr(self, ch, curr):

def get_volt(self, ch):
self.set_chan(ch)
if (self.numChannels != 1):
if (self.num_channels != 1):
self.write('MEAS:VOLT? CH' + str(ch))
else:
self.write('MEAS:VOLT?')
Expand All @@ -138,7 +145,7 @@ def get_volt(self, ch):

def get_curr(self, ch):
self.set_chan(ch)
if (self.numChannels != 1):
if (self.num_channels != 1):
self.write('MEAS:CURR? CH' + str(ch))
else:
self.write('MEAS:CURR?')
Expand Down

0 comments on commit fa297e7

Please sign in to comment.