Skip to content

initial muxer implementation #219

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3097b60
initial muxer implementation
Feb 6, 2025
5a36087
two files to connect muxer to dripline service
miniwynne Mar 19, 2025
37d26bd
added RelayService by copying old spime_endpoints.py
miniwynne Apr 2, 2025
23e118e
closed the comment that was commenting out all of RelayService
miniwynne Apr 30, 2025
d0eb97c
commenting out the error lines
miniwynne May 1, 2025
32b43e2
added an 'append.MuxerRelay' above the relay class and fixed a commen…
miniwynne May 5, 2025
52e578c
added an 'Enitity.__init__(self,**kwargs) and hopefully fixed the ind…
miniwynne May 5, 2025
b30672a
changed the tabs around using 'expand -t 4'
miniwynne May 5, 2025
1f9d282
changed 'Entity.__init__(self,**kwargs)' to be at the end of Relay
miniwynne May 6, 2025
4722d3b
trying to address the get_str eror using pop
miniwynne May 6, 2025
d21d26b
added self. in front of any kwargs, hoping I didnt break spacing
miniwynne May 6, 2025
cf1000b
did away with adding self. to all objects, ended up doing the kwargs.…
miniwynne May 6, 2025
8ae9e0b
changing the input to MuxerRelay from Entity to FormatEntity
miniwynne May 7, 2025
3985355
importing FormatEntity from implementations
miniwynne May 7, 2025
854ae0b
removed ' ' from get_str to see if that is the issue
miniwynne May 7, 2025
62e4524
putting self. in front get_str
miniwynne May 7, 2025
97cfa8b
adding the kwargs.pop thing again to get_str
miniwynne May 7, 2025
c01ccbe
Fixing super __init__ for Relay
May 7, 2025
da79744
indentation issue at line 147 w calibration
miniwynne May 7, 2025
21518e0
putting get_str back into a string
miniwynne May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dripline/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

# Modules in this directory
from .add_auth_spec import *
from .muxer_service import *
155 changes: 155 additions & 0 deletions dripline/extensions/muxer_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
'''
A class to interface with the multiplexer aka muxer instrument
'''

from dripline.core import ThrowReply, Entity, calibrate
from dripline.implementations import EthernetSCPIService, FormatEntity

import logging
logger = logging.getLogger(__name__)

__all__ = []
__all__.append('MuxerService')

class MuxerService(EthernetSCPIService):
'''
Provider to interface with muxer
'''

def __init__(self, scan_interval=0,**kwargs):
'''
scan_interval (int): time between scans in seconds
'''
EthernetSCPIService.__init__(self,**kwargs)
if scan_interval <= 0:
raise ThrowReply('service_error_invalid_value', 'scan interval must be > 0')
self.scan_interval = scan_interval
self.configure_scan()

def configure_scan(self, *args, **kwargs):
'''
loops over the provider's internal list of endpoints and attempts to configure each, then configures and begins scan
'''
self.send_to_device(['ABOR;*CLS;*OPC?'])

ch_scan_list = list()
for childname, child in self.sync_children.items():

if not isinstance(child, MuxerGetEntity):
continue
error_data = self.send_to_device([child.conf_str+';*OPC?','SYST:ERR?'])
if error_data != '1;+0,"No error"':
logger.critical('Error detected; cannot configure muxer')
raise ThrowReply('resource_error',
f'{error_data} when attempting to configure endpoint <{childname}>')

ch_scan_list.append(str(child.ch_number))
child.log_interval = self.scan_interval

scan_list_cmd = 'ROUT:SCAN (@{})'.format(','.join(ch_scan_list))
self.send_to_device([scan_list_cmd+';*OPC?',\
'TRIG:SOUR TIM;*OPC?',\
'TRIG:COUN INF;*OPC?',\
'TRIG:TIM {};*OPC?'.format(self.scan_interval),\
'INIT;*ESE?'])


__all__.append('MuxerGetEntity')
class MuxerGetEntity(Entity):
'''
Entity for communication with muxer endpoints. No set functionality.
'''

def __init__(self,
ch_number,
conf_str=None,
**kwargs):
'''
ch_number (int): channel number for endpoint
conf_str (str): used by MuxerService to configure endpoint scan
'''
Entity.__init__(self, **kwargs)
if conf_str is None:
raise ThrowReply('service_error_invalid_value',
f'<conf_str> required for MuxerGetEntity {self.name}')
self.get_str = "DATA:LAST? (@{})".format(ch_number)
self.ch_number = ch_number
self.conf_str = conf_str.format(ch_number)

@calibrate()
def on_get(self):
result = self.service.send_to_device([self.get_str.format(self.ch_number)])
logger.debug('very raw is: {}'.format(result))
return result.split()[0]

def on_set(self, value):
raise ThrowReply('message_error_invalid_method',
f'endpoint {self.name} does not support set')



__all__.append('MuxerRelay')
class MuxerRelay(FormatEntity):
'''
Entity to communicate with relay cards in muxer,
'''
def __init__(self,
ch_number,
relay_type=None,
**kwargs):
'''
ch_number (int): channel number for endpoint
relay_type (None,'relay','polarity','switch'): automatically configure set_value_map and calibration dictionaries (overwriteable)
'''

# default get/set strings
if 'get_str' not in kwargs:
if relay_type=='relay' or relay_type=='polarity':
kwargs.update( {'get_str':':ROUTE:OPEN? (@{})'.format(ch_number)} )
elif relay_type=='switch':
kwargs.update( {'get_str':':ROUTE:CLOSE? (@{})'.format(ch_number)} )
if 'set_str' not in kwargs:
kwargs.update( {'set_str':':ROUTE:{{}} (@{});{}'.format(ch_number,kwargs['get_str'])} )
# Default kwargs for get_on_set and set_value_lowercase
if 'get_on_set' not in kwargs:
kwargs.update( {'get_on_set':True} )
if 'set_value_lowercase' not in kwargs:
kwargs.update( {'set_value_lowercase' :True} )
# Default set_value_map and calibration for known relay types (relay, polarity, switch)
if relay_type == 'relay':
if 'set_value_map' not in kwargs:
kwargs.update( { 'set_value_map' : {1: 'OPEN',
0: 'CLOSE',
'on': 'OPEN',
'off': 'CLOSE',
'enable': 'OPEN',
'disable': 'CLOSE'} } )
if 'calibration' not in kwargs:
kwargs.update( { 'calibration' : {'1': 'enabled',
'0': 'disabled'} } )
elif relay_type == 'polarity':
if 'set_value_map' not in kwargs:
kwargs.update( { 'set_value_map' : {1: 'OPEN',
0: 'CLOSE',
'positive': 'OPEN',
'negative': 'CLOSE'} } )
if 'calibration' not in kwargs:
kwargs.update( { 'calibration' : {'1': 'positive',
'0': 'negative'} } )
elif relay_type == 'switch':
if 'set_value_map' not in kwargs:
kwargs.update( { 'set_value_map' : {0: 'OPEN',
1: 'CLOSE',
'off': 'OPEN',
'on': 'CLOSE',
'disable': 'OPEN',
'enable': 'CLOSE'} } )
if 'calibration' not in kwargs:
kwargs.update( { 'calibration' : {'0': 'disabled',
'1': 'enabled'} } )
elif relay_type is not None:
raise ThrowReply("message_error_invalid_method",
f"endpoint {self.name} expect 'relay'or 'polarity'")

FormatEntity.__init__(self, **kwargs)

31 changes: 31 additions & 0 deletions muxer-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: "3"
services:

# The broker for the mesh
rabbit-broker:
image: rabbitmq:3-management
ports:
- "15672:15672"
environment:
- RABBITMQ_DEFAULT_USER=dripline
- RABBITMQ_DEFAULT_PASS=dripline
healthcheck:
test: ["CMD-SHELL", "curl -u dripline:dripline http://rabbit-broker:15672/api/overview &> /dev/null || exit 1"]

muxer-service:
image: ghcr.io/project8/dragonfly:muxer_test
depends_on:
rabbit-broker:
condition: service_healthy
volumes:
- ./muxer.yaml:/root/muxer.yaml
environment:
- DRIPLINE_USER=dripline
- DRIPLINE_PASSWORD=dripline
command:
- dl-serve
- -c
- /root/muxer.yaml
- -vv
- -b
- rabbit-broker
65 changes: 65 additions & 0 deletions muxer.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: muxer
module: MuxerService
socket_info: ('glenlivet.p8', 5024)
cmd_at_reconnect:
-
- ""
- "SYST:ERR?"
- "TRIG:DEL:AUTO?"
command_terminator: "\r\n"
response_terminator: "\r\n34980A> "
reply_echo_cmd: True
scan_interval: 30
endpoints:
##################### Cable B ####################
# PT 100 1/12
- name: pt100_1_12
module: MuxerGetEntity
ch_number: 1011
conf_str: 'CONF:FRES AUTO,DEF,(@{})'
calibration: 'pt100_calibration({})'
# PT 100 2/12
- name: pt100_2_12
module: MuxerGetEntity
ch_number: 1012
conf_str: 'CONF:FRES AUTO,DEF,(@{})'
calibration: 'pt100_calibration({})'
##################### Cable C ####################
# PT 100 3/12
- name: pt100_3_12
module: MuxerGetEntity
ch_number: 1004
conf_str: 'CONF:FRES AUTO,DEF,(@{})'
calibration: 'pt100_calibration({})'
# PT 100 4/12
- name: pt100_4_12
module: MuxerGetEntity
ch_number: 1005
conf_str: 'CONF:FRES AUTO,DEF,(@{})'
calibration: 'pt100_calibration({})'
# PT 100 5/12
- name: pt100_5_12
module: MuxerGetEntity
ch_number: 1006
conf_str: 'CONF:FRES AUTO,DEF,(@{})'
calibration: 'pt100_calibration({})'
# PT 100 6/12
- name: pt100_6_12
module: MuxerGetEntity
ch_number: 1007
conf_str: 'CONF:FRES AUTO,DEF,(@{})'
calibration: 'pt100_calibration({})'
# PT 100 7/12
## - name: pt_100_7_12
## modeule: MuxerGetEntity
## ch_number: 1013
## conf_str: 'CONF:FRES AUTO,DEF,(@{})'
## calibration: 'pt100_calibration({})'

# this is not set up but wanted to keep the syntax available as an example
- name: hall_probe_field
module: MuxerGetEntity
ch_number: 1029
conf_str: 'CONF:VOLT:DC 10,(@{})'
calibration: "(0.9991/0.847)*(1000*{}+0.007)"

Loading