Commit a70daeeb authored by Romain Baptiste Dominique Albert's avatar Romain Baptiste Dominique Albert
Browse files

Merge remote-tracking branch 'origin/SignalHoundServer' into integrated_swept

parents 3bbb1f35 de4b1ffb
......@@ -6,21 +6,18 @@ Created on Tue May 7 10:21:49 2019
"""
from UtilitiesLib import progressive_plot_2d
#from IPython import display
import lmfit
import Instruments
import time
class IQCal_base(object):
from .CALPAR import CalibrationParameters
import numpy as np
import time
import matplotlib.pyplot as plt
#----------------------------------------------------------------------------------------------------------------------------Initialization of the Class-----------------------
# Initialization of the Class ##############################################
def __init__(self, sgLO, SpecAna, OS='W', calibration_file = None):
"""
This object contains the calibration parameters of an IQAM.
......@@ -47,13 +44,12 @@ class IQCal_base(object):
are initialized.
"""
self.connect_specana(SpecAna,OS)
# Init Spectrum Analyzer
self._SpecAna = None
self.connect_specana(SpecAna, OS)
# Local Oscillator
self._sgLO = sgLO
if calibration_file is not None:
self.load_calibration(calibration_file)
else:
......@@ -72,10 +68,10 @@ class IQCal_base(object):
cal_dict = calibration
self.calibration = self.CalibrationParameters(dictionary=cal_dict)
def connect_specana(self,ID=None,OS='W'):
"""Connect the specified spectrum analyzer using the driver for the specified operative system
"""Connect the specified spectrum analyzer using the driver for the
specified operative system
args:
- ID: 'SHN' for Signal Hound N
......@@ -92,14 +88,22 @@ class IQCal_base(object):
if ID is None:
ID = self._SpecAnaID
# ToDo: Integrate SignalHound to SA Instrument Class to prevent this
# madness.
# Rohde und Schwarz
if ID == 'RS':
self._SpecAna = Instruments.SA('SA1','').instr
self._SpecAna._inst.timeout=5e3
self._SpecAna = Instruments.SA('SA1', '').instr
self._SpecAna._inst.timeout = 5e3
# Remote SignalHound
# Signalhound is connected to a computer where a server script runs
elif ID[:3] == 'SHR':
from Instruments.Drivers.SignalHound.client import SignalHoundClient
self._SpecAna = SignalHoundClient(id=ID)
# SignalHound directly connected
elif ID[:2] == 'SH':
from SIGNALHOUND import SignalHound
self._SpecAna = SignalHound(ID,OS=OS)
self._SpecAna = SignalHound(ID, OS=OS)
else:
print('Wrong spectrum analyzer specified')
raise Exception('SpecAnaERR')
......
......@@ -11,6 +11,7 @@ import numpy as np
from Instruments.core import Instrument, update_db, check_db
from DataHandling.core import Parameter, Measurement, DataSet
class CS(Instrument):
"""DC Source Instrument class.
......@@ -80,6 +81,7 @@ class CS(Instrument):
self.driver = driver
# Connect to device ####################################################
self.instr = None
self.init_driver()
print("{cs} - Channel {channel}".format(cs=id_string, channel=channel))
......@@ -114,7 +116,7 @@ class CS(Instrument):
def init_driver(self):
"""Init connection to device."""
self.instr = self.driver(self.ip, self.ch, cur_lim=self.cur_lim,
vol_lim=self.vol_lim,**self.kwargs)
vol_lim=self.vol_lim, **self.kwargs)
def start(self):
self.output('ON')
......@@ -164,7 +166,6 @@ class CS(Instrument):
safe_mode : bool
Raises an error if limits are exceeded
"""
resp = self.instr.output_level(arg=arg,
safe_mode=safe_mode)
if str(arg) != "?":
......
......@@ -5,21 +5,10 @@ Module for Digital Attenuators
Author: Christian Schneider <c.schneider@uibk.ac.at>
Date: 16.08.2019
"""
from IPLIST import IPList
from Instruments.core import Instrument, update_db, check_db
# Load database if connection is there
try:
from Monitor.functions import update_db, check_db
except:
def update_db(dummy):
return
def check_db(dummy):
return
class DA(object):
class DA(Instrument):
"""Digital Attenuator Instrument Class
Requires that the device is listed in the IPList. Otherwise the driver has
......@@ -47,30 +36,12 @@ class DA(object):
errors you can try to set it to False
"""
def __init__(self, id_string, cryostat, channel=0, driver=None, database=True):
def __init__(self, id_string, channel=0, driver=None, database=True):
# Device parameters ####################################################
try:
# Try to find device in IPList
self.ip = IPList[id_string]
except KeyError:
# If DA is not specified by valid IPList entry. Try directly ip
if driver is not None:
self.ip = id_string
else:
raise Exception('DA not in IPList. Please specify driver')
self.CryoID = cryostat
self.ch = channel
self.id = id_string
# Database parameters ##################################################
super().__init__(id_string, kwargs, driver, database)
self.ch = int(channel)
self.devtype = 'DA'
self.dB_ID = None
if database:
self.db = True
check_db(self)
else:
self.db = False
# Import and load drivers ##############################################
if id_string[:3] == 'DA1':
......@@ -86,11 +57,10 @@ class DA(object):
self.driver = driver
# Start connection to device ###########################################
self.instr = None
self.init_driver()
# Print information ####################################################
print("Identify: " + self.identify()) # Identify at beginning
self.print_identity()
print('Maximum Attenuation: {} dB'.format(self.instr.max_attenuation))
print('Attenuation Step: {} dB'.format(self.instr.step_attenuation))
......@@ -98,21 +68,6 @@ class DA(object):
# Update database
update_db(self)
def identify(self):
"""Identify device. Returns a typical string indicating manufacturer
and firmware version
"""
return self.instr.identify()
def init_driver(self):
"""Init connection to device."""
self.instr = self.driver(self.ip, self.ch)
def close_driver(self):
"""Close connection to device"""
self.instr.close()
self.instr = None
# Basic functions ##########################################################
def attenuation(self, att='?'):
"""Set/query attenuation.
......
......@@ -27,7 +27,7 @@ class APMS(object):
Timeout for anapico device in seconds. By default set to 1800 s.
"""
def __init__(self, instr, channel, timeout=1800):
def __init__(self, instr, channel, timeout=1800, **kwargs):
self.version = '2.1.0'
self.inst = instr
self.channel = channel
......
......@@ -21,7 +21,7 @@ class APMS(object):
IP address of signal generator
"""
def __init__(self, ip, *args):
def __init__(self, ip, *args, **kwargs):
self.version = '1.0.0'
self.ip = ip
# Initialize device
......@@ -85,7 +85,6 @@ class APMS(object):
self.__channel = channel
def output(self, arg='?'):
"""Turn RF output power on/off."""
return self.com(':OUTP{}'.format(self.__channel), arg)
......
......@@ -28,7 +28,7 @@ class APSIN(object):
Timeout in seconds for Anapicos. Set by default to 1800 seconds.
"""
def __init__(self, ip, channel=1, timeout=1800):
def __init__(self, ip, channel=1, timeout=1800, **kwargs):
self.version = '1.0.0'
self.ip = ip
# Initialize device
......
......@@ -15,7 +15,7 @@ print('BK Precision v' + version)
class BKP_SG(object):
global version
def __init__(self, resID):
def __init__(self, resID, **kwargs):
self.version = version
self.resID = resID
self._channelOpts = ['C1', 'C2']
......
......@@ -22,7 +22,7 @@ class B29XX(object):
"""
def __init__(self, ip, channel, reset=False,
cur_lim=1e-3, vol_lim=100e-3):
cur_lim=1e-3, vol_lim=100e-3, **kwargs):
self.version = '3.0.2'
self.ip = ip
......
......@@ -5,7 +5,6 @@
Driver for ENA E5071C and E5063A
"""
import pyvisa as visa
import time
import numpy as np
......
......@@ -35,7 +35,7 @@ class EXG(object):
IP address of signal generator
"""
def __init__(self, ip, *args):
def __init__(self, ip, *args, **kwargs):
self.version = '1.1.0'
self.ip = ip
# Initialize device
......
......@@ -19,7 +19,7 @@ class T7Pro(object):
ip : str
IP Address of the device
"""
def __init__(self, ip, *pars):
def __init__(self, ip, *pars, **kwargs):
self.ip = ip
self.h = ljm.openS("T7", "ETHERNET", self.ip)
self.res_tables = self.init_res_tables()
......
"""
Python class to run a driver as a server class
"""
import argparse
parser = argparse.ArgumentParser(description='Server for an instrument driver')
parser.add_argument('driver', metavar='Magnicon.XXF', type=str,
help='Name of the class to run as driver server')
parser.add_argument('port', metavar=9001, type=int,
help='Port')
import socketserver
import re
import pickle
import socket
class MagniconServer(socketserver.StreamRequestHandler):
"""
Request handler for Magnicon Data
"""
def handle(self):
"""Handle incoming function calls"""
# Get command
self.data = self.rfile.readline().strip().decode('utf-8')
# get name and arguments by using regular expressions
p = r'^(?P<function>[\w\d_\-]+)\((?P<args>[\w\s\?\-\,=.\[\]\'\"]*)\)$'
m = re.match(p, self.data).groupdict()
if m['function'] in Instrument.__dir__():
command = 'Instrument.' + self.data
resp = eval(command)
self.wfile.write(pickle.dumps(resp))
if __name__ == '__main__':
host = socket.gethostname()
port = parser.port
import_string = 'import ' + parser.driver
exec(import_string)
Instrument = exec(parser.driver+'()')
with socketserver.TCPServer((host, port), MagniconServer) as server:
server.serve_forever()
......@@ -13,7 +13,7 @@ VERSION = '1.0.0'
class RCDAT(object):
"""Instrument Driver for Minicircuits Step Attenuator"""
def __init__(self, ip, *pars):
def __init__(self, ip, *pars, **kwargs):
"""
*pars are not used, however required
to be compatible to other devices.
......
......@@ -17,7 +17,7 @@ import struct
class FSV30(object):
"""Instrument Driver for RohdeSchwarz FSV30 Spectrum Analyzer"""
def __init__(self, ip, *pars):
def __init__(self, ip, *pars, **kwargs):
"""
*pars are not used, however required
to be compatible to other devices.
......
......@@ -12,7 +12,7 @@ VERSION = '1.0.0'
class RSC(object):
"""Instrument Driver for RohdeSchwarz Step Attenuator"""
def __init__(self, ip, channel=0, *pars):
def __init__(self, ip, channel=0, *pars, **kwargs):
"""
*pars are not used, however required
to be compatible to other devices.
......
This diff is collapsed.
"""
A socket client to talk to a running server
author: C. Schneider <c.schneider@uibk.ac.at>
date: 30.09.2021
"""
import inspect
import pickle
import socket
from types import FunctionType
from IPLIST import IPList
from SIGNALHOUND import SignalHound
class SignalHoundClient(object):
"""
Communicates with a Signalhound Server.
Parameters
-----------
id : str
ID according to IPList for remote Signalhound.
See https://kirchmair.iqoqi.at/lab/dashboard/devices/ip
"""
def __init__(self, id):
# Obtain host ip and port
ip = IPList[id]
self.host = ip.split(":")[0]
self.port = int(ip.split(":")[1])
# Inherit methods from instrument class
methods = [x for x,y in SignalHound.__dict__.items() if
isinstance(y, FunctionType) and x[0] != "_"]
for m in methods:
# Get all args
sig = inspect.signature(SignalHound.__dict__[m])
args = str(sig).strip('()')
# Get args without default value and self
ks = inspect.signature(SignalHound.__dict__[m]).parameters.keys()
args2 = ''.join((i + ',') for i in ks)[5:-1]
# Wrapper code
wrapper_code = 'def {name}({args}):\n' \
' return self.send("{name}("+str([{args2}]).' \
'strip("[]")+")")'
ld = {}
exec(wrapper_code.format(name=m,
args=args,
args2=args2 # Args without self
),
None, ld)
# Inherit Documentation
ld[m].__doc__ = SignalHound.__dict__[m].__doc__
# Set methods
setattr(self.__class__, m, ld[m])
def send(self, string):
# Open socket only temporary
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Send command
sock.connect((self.host, self.port))
sock.sendall(bytes(string + '\n', 'utf-8'))
# Wait for reply
rec_data = b''
while True:
block = sock.recv(4096)
if not block: break
rec_data += block
return pickle.loads(rec_data)
def close(self):
"""Dummy function"""
return None
"""
Python class to run a driver as a server class
"""
import argparse
import socketserver
import re
import pickle
import socket
parser = argparse.ArgumentParser(description='Server for an instrument driver')
parser.add_argument('driver', metavar='Magnicon.XXF', type=str,
parser.add_argument('id', metavar='SH1',
type=str,
help='Name of the class to run as driver server')
parser.add_argument('port', metavar=9001, type=int,
help='Port')
import socketserver
import re
import pickle
import socket
class MagniconServer(socketserver.StreamRequestHandler):
class Server(socketserver.StreamRequestHandler):
"""
Request handler for Magnicon Data
Request handler for instruments.
"""
def handle(self):
"""Handle incoming function calls"""
# Get command
self.data = self.rfile.readline().strip().decode('utf-8')
data = self.rfile.readline().strip().decode('utf-8')
print(data)
# get name and arguments by using regular expressions
p = r'^(?P<function>[\w\d_\-]+)\((?P<args>[\w\s\?\-\,=.\[\]\'\"]*)\)$'
m = re.match(p, self.data).groupdict()
m = re.match(p, data).groupdict()
# If command is a valid command of the instrument, execute it
if m['function'] in Instrument.__dir__():
command = 'Instrument.' + self.data
command = 'Instrument.' + data
# Execute command
resp = eval(command)
# Send response back to client
self.wfile.write(pickle.dumps(resp))
if __name__ == '__main__':
host = socket.gethostname()
port = parser.port
args = parser.parse_args()
port = args.port
# Print information
print("Starting up server...")
print("To stop the server press Ctrl+C ")
import_string = 'import ' + parser.driver
exec(import_string)
# Init driver
from SIGNALHOUND import SignalHound
Instrument = SignalHound(args.id)
print("Driver connected to Signalhound:")
print(Instrument.GetSerialNumber())
Instrument = exec(parser.driver+'()')
with socketserver.TCPServer((host, port), MagniconServer) as server:
# Listen to specified port
with socketserver.TCPServer((host, port), Server) as server:
server.serve_forever()
......@@ -17,7 +17,7 @@ import pyvisa as visa
class RSA5115B(object):
"""Instrument Driver for Tektronix RSA5115B Spectum analyzer"""
def __init__(self, ip, *pars):
def __init__(self, ip, *pars, **kwargs):
"""Driver for RSA5115B. *pars are not used, however required
to be compatible to other devices.
......
......@@ -17,7 +17,7 @@ VERSION = '1.2.0'
class V5015(object):
def __init__(self, ip, channel=1):
def __init__(self, ip, channel=1, **kwargs):
self.__version__ = VERSION
self.ip = ip
rm = visa.ResourceManager('@py')
......@@ -43,29 +43,28 @@ class V5015(object):
self.serialnumber = self.identify().split(', ')[2]
# initializing power
self.output('OFF')
self.power(-30)
self.amp_modulation(0)
self.amp_mod_frequency(1000)
#self.output('OFF')
#self.power(-30)
#self.amp_modulation(0)
#self.amp_mod_frequency(1000)
# initializing frequency
self.mode('CW')
self.frequency(np.round(np.float(self.serialnumber)*1e-9,9))
self.frequency_offset(0)
self.frequency_step(0)
self.sweep_start(1)
self.sweep_stop(10)
self.sweep_stepsize(0.1)
self.sweep_rate(100)
self.sweep_rtime(0)
self.sweep_triggermode('AUTO')
#self.mode('CW')
#self.frequency(np.round(np.float(self.serialnumber)*1e-9,9))
#self.frequency_offset(0)
#self.frequency_step(0)
#self.sweep_start(1)
#self.sweep_stop(10)
#self.sweep_stepsize(0.1)
#self.sweep_rate(100)
#self.sweep_rtime(0)
#self.sweep_triggermode('AUTO')
# initializing reference and spur mitigation
self.reference_trim(120) # default by manufacturere, do not change it, since it can harm other devices connected to the external frequency port!!!
self.reference_frequency(10)
#self.reference_trim(120) # default by manufacturere, do not change
# it, since it can harm other devices connected to the external frequency port!!!
self.reference_frequency(10e6)
self.reference(1)
self.spur_mitigation_mode('LN1')
self.valon_full_query('ID')
#self.valon_full_query('ID')
# ----------------------- --
......@@ -485,29 +484,30 @@ class V5015(object):
# ---------------------- --
# Configuration Commands
# ------------------------ --- -
def reference_frequency(self, arg='?'):
""" Sets the expected external and internal reference frequency in units of Hz.
Be sure that they match, else the synthesizer performs unstable.
The default reference frequency is 10 MHz.