Skip to content

Commit 50d3873

Browse files
committed
Merge branch 'temp_branch' into add_isis_devices_2
This merges history of https://github.com/ISISComputingGroup/EPICS-DeviceEmulator into lewis
2 parents da8616c + 69c65e6 commit 50d3873

File tree

367 files changed

+23678
-89
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

367 files changed

+23678
-89
lines changed

.git-blame-ignore-revs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# ignore ruff format and --fix
2+
7d074d129ef30f64dee361531fe3d6a020cdff98
3+
3c5addd30d6e6f6ae34b02333d34360d773ed3bf

lewis/devices/Lksh218/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .device import SimulatedLakeshore218
2+
3+
__all__ = ["SimulatedLakeshore218"]

lewis/devices/Lksh218/device.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from collections import OrderedDict
2+
3+
from lewis.devices import StateMachineDevice
4+
5+
from .states import DefaultState
6+
7+
NUMBER_OF_TEMP_CHANNELS = 8
8+
NUMBER_OF_SENSOR_CHANNELS = 8
9+
10+
11+
class SimulatedLakeshore218(StateMachineDevice):
12+
"""Simulated Lakeshore 218
13+
"""
14+
15+
def _initialize_data(self):
16+
"""Sets the initial state of the device.
17+
"""
18+
self._temps = [1.0] * NUMBER_OF_TEMP_CHANNELS
19+
self._sensors = [0.5] * NUMBER_OF_SENSOR_CHANNELS
20+
self.temp_all = ""
21+
self.sensor_all = ""
22+
self.connected = True
23+
24+
@staticmethod
25+
def _get_state_handlers():
26+
"""Returns: States and their names.
27+
"""
28+
return {DefaultState.NAME: DefaultState()}
29+
30+
@staticmethod
31+
def _get_initial_state():
32+
"""Returns: The name of the initial state.
33+
"""
34+
return DefaultState.NAME
35+
36+
@staticmethod
37+
def _get_transition_handlers():
38+
"""Returns: The state transitions.
39+
"""
40+
return OrderedDict()
41+
42+
def get_temp(self, number):
43+
"""Gets the temperature of a specific temperature sensor.
44+
45+
Args:
46+
number: Integer between 1 and 8.
47+
48+
Returns:
49+
float: Temperature value at position (number - 1) in temps.
50+
"""
51+
return self._temps[number - 1]
52+
53+
def set_temp(self, number, temperature):
54+
"""Sets the (number - 1) temp pv to temperature.
55+
56+
Args:
57+
number: Integer between 1 and 8.
58+
temperature: Temperature reading to set.
59+
60+
Returns:
61+
None
62+
"""
63+
self._temps[number - 1] = temperature
64+
65+
def get_sensor(self, number):
66+
"""Gets the sensor reading of a specific sensor.
67+
68+
Args:
69+
number: Integer between 1 and 8.
70+
71+
Returns:
72+
float: Value of sensor at position (number - 1) in sensors.
73+
"""
74+
return self._sensors[number - 1]
75+
76+
def set_sensor(self, number, value):
77+
"""Sets the (number - 1) sensor pv to value.
78+
79+
Args:
80+
number: Integer between 1 and 8.
81+
value: Sensor reading to set.
82+
83+
Returns:
84+
None
85+
"""
86+
self._sensors[number - 1] = value
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .stream_interface import Lakeshore218StreamInterface
2+
3+
__all__ = ["Lakeshore218StreamInterface"]
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from lewis.adapters.stream import StreamInterface
2+
from lewis.utils.command_builder import CmdBuilder
3+
4+
5+
def if_connected(f):
6+
"""Decorator that executes f if the device is connected and returns None otherwise.
7+
8+
Args:
9+
f: function to be executed if the device is connected.
10+
11+
Returns:
12+
The value of f(*args) if the device is connected and None otherwise.
13+
"""
14+
15+
def wrapper(*args):
16+
connected = getattr(args[0], "_device").connected
17+
if connected:
18+
result = f(*args)
19+
else:
20+
result = None
21+
return result
22+
23+
return wrapper
24+
25+
26+
class Lakeshore218StreamInterface(StreamInterface):
27+
"""Stream interface for the serial port
28+
"""
29+
30+
in_terminator = "\r\n"
31+
out_terminator = "\r\n"
32+
33+
commands = {
34+
CmdBuilder("get_temp").escape("KRDG? ").arg("[1-8]").build(),
35+
CmdBuilder("get_sensor").escape("SRDG? ").arg("[1-8]").build(),
36+
CmdBuilder("get_temp_all").escape("KRDG? 0").build(),
37+
CmdBuilder("get_sensor_all").escape("SRDG? 0").build(),
38+
}
39+
40+
@if_connected
41+
def get_temp(self, number):
42+
"""Returns the temperature of a TEMP pv.
43+
44+
Args:
45+
number: integer between 1 and 8
46+
47+
Returns:
48+
float: temperature
49+
"""
50+
number = int(number)
51+
temperature = self._device.get_temp(number)
52+
return temperature
53+
54+
@if_connected
55+
def get_sensor(self, number):
56+
"""Returns the temperature of a SENSOR pv.
57+
58+
Args:
59+
number: integer between 1 and 8
60+
61+
Returns:
62+
float: sensor_reading
63+
"""
64+
number = int(number)
65+
sensor_reading = self._device.get_sensor(number)
66+
return sensor_reading
67+
68+
@if_connected
69+
def get_temp_all(self):
70+
"""Returns a string from TEMPALL pv.
71+
72+
Returns:
73+
string: value of TEMPALL pv.
74+
"""
75+
return self._device.temp_all
76+
77+
@if_connected
78+
def get_sensor_all(self):
79+
"""Returns a string from SENSORALL pv.
80+
81+
Returns:
82+
string: value of SENSORALL pv.
83+
"""
84+
return self._device.sensor_all

lewis/devices/Lksh218/states.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from lewis.core.statemachine import State
2+
3+
4+
class DefaultState(State):
5+
"""Device is in default state.
6+
"""
7+
8+
NAME = "Default"

lewis/devices/ag33220a/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from ..lewis_versions import LEWIS_LATEST
2+
from .device import SimulatedAG33220A
3+
4+
framework_version = LEWIS_LATEST
5+
__all__ = ["SimulatedAG33220A"]

lewis/devices/ag33220a/device.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
from lewis.devices import Device
2+
3+
4+
class SimulatedAG33220A(Device):
5+
"""Simulated AG33220A
6+
"""
7+
8+
connected = True
9+
10+
# Constants
11+
AMP_MIN = 0.01
12+
AMP_MAX = 10
13+
OFF_MAX = 4.995
14+
VOLT_MAX = 5
15+
VOLT_MIN = -5
16+
VOLT_LOW_MAX = 4.99
17+
VOLT_HIGH_MIN = -4.99
18+
VOLT_PRECISION = 0.01
19+
FREQ_MINS = {
20+
"SIN": 10**-6,
21+
"SQU": 10**-6,
22+
"RAMP": 10**-6,
23+
"PULS": 5 * 10**-4,
24+
"NOIS": 10**-6,
25+
"USER": 10**-6,
26+
}
27+
FREQ_MAXS = {
28+
"SIN": 2 * 10**7,
29+
"SQU": 2 * 10**7,
30+
"RAMP": 2 * 10**5,
31+
"PULS": 5 * 10**6,
32+
"NOIS": 2 * 10**7,
33+
"USER": 6 * 10**6,
34+
}
35+
36+
# Device variables
37+
idn = "Agilent Technologies,33220A-MY44033103,2.02-2.02-22-2"
38+
amplitude = 0.1
39+
frequency = 1000
40+
offset = 0
41+
units = "VPP"
42+
function = "SIN"
43+
output = "ON"
44+
voltage_high = 0.05
45+
voltage_low = -0.05
46+
range_auto = "OFF"
47+
48+
def limit(self, value, minimum, maximum):
49+
"""Limits an input number between two given numbers or sets the value to the maximum or minimum.
50+
51+
:param value: the value to be limited
52+
:param minimum: the smallest that the value can be
53+
:param maximum: the largest that the value can be
54+
55+
:return: the value after it has been limited
56+
"""
57+
if type(value) is str:
58+
try:
59+
value = float(value)
60+
except ValueError:
61+
return {"MIN": minimum, "MAX": maximum}[value]
62+
63+
return max(min(value, maximum), minimum)
64+
65+
def set_new_amplitude(self, new_amplitude):
66+
"""Changing the amplitude to the new amplitude whilst also changing the offset if voltage high or low is
67+
outside the boundary. The volt high and low are then updated.
68+
69+
:param new_amplitude: the amplitude to set the devices amplitude to
70+
"""
71+
new_amplitude = self.limit(new_amplitude, self.AMP_MIN, self.AMP_MAX)
72+
73+
peak_amp = 0.5 * new_amplitude
74+
if self.offset + peak_amp > self.VOLT_MAX:
75+
self.offset = self.VOLT_MAX - peak_amp
76+
elif self.offset - peak_amp < self.VOLT_MIN:
77+
self.offset = self.VOLT_MIN + peak_amp
78+
79+
self.amplitude = new_amplitude
80+
81+
self._update_volt_high_and_low(self.amplitude, self.offset)
82+
83+
def set_new_frequency(self, new_frequency):
84+
"""Sets the frequency within limits between upper and lower bound (depends on the function).
85+
86+
:param new_frequency: the frequency to set to
87+
"""
88+
self.frequency = self.limit(
89+
new_frequency, self.FREQ_MINS[self.function], self.FREQ_MAXS[self.function]
90+
)
91+
92+
def set_new_voltage_high(self, new_voltage_high):
93+
"""Sets a new voltage high which then changes the voltage low to keep it lower.
94+
The voltage offset and amplitude are then updated.
95+
96+
:param new_voltage_high: the value of voltage high to set to
97+
"""
98+
new_voltage_high = self.limit(new_voltage_high, self.VOLT_HIGH_MIN, self.VOLT_MAX)
99+
if new_voltage_high <= self.voltage_low:
100+
self.voltage_low = self.limit(
101+
new_voltage_high - self.VOLT_PRECISION, self.VOLT_MIN, new_voltage_high
102+
)
103+
self._update_volt_and_offs(self.voltage_low, new_voltage_high)
104+
105+
def set_new_voltage_low(self, new_voltage_low):
106+
"""Sets a new voltage high which then changes the voltage low to keep it higher.
107+
The voltage offset and amplitude are then updated.
108+
109+
:param new_voltage_low: the value of voltage low which is to be set
110+
"""
111+
new_voltage_low = self.limit(new_voltage_low, self.VOLT_MIN, self.VOLT_LOW_MAX)
112+
if new_voltage_low >= self.voltage_high:
113+
self.voltage_high = self.limit(
114+
new_voltage_low + self.VOLT_PRECISION, new_voltage_low, self.VOLT_MAX
115+
)
116+
self._update_volt_and_offs(new_voltage_low, self.voltage_high)
117+
118+
def _update_volt_and_offs(self, new_low, new_high):
119+
"""Updates the value of amplitude and offset if there is a change in voltage low or voltage high.
120+
121+
:param new_low: the value of voltage low
122+
:param new_high: the value of voltage high
123+
"""
124+
self.voltage_high = new_high
125+
self.voltage_low = new_low
126+
self.amplitude = self.voltage_high - self.voltage_low
127+
self.offset = (self.voltage_high + self.voltage_low) / 2
128+
129+
def set_offs_and_update_voltage(self, new_offset):
130+
"""Sets the value of offset and updates the amplitude, voltage low and voltage high for a new value of the offset.
131+
132+
:param new_offset: the new offset to be set
133+
"""
134+
new_offset = self.limit(new_offset, -self.OFF_MAX, self.OFF_MAX)
135+
if new_offset + self.voltage_high > self.VOLT_MAX:
136+
self.amplitude = 2 * (self.VOLT_MAX - new_offset)
137+
self.voltage_high = self.VOLT_MAX
138+
self.voltage_low = self.VOLT_MAX - self.amplitude
139+
elif new_offset + self.voltage_low < self.VOLT_MIN:
140+
self.amplitude = 2 * (self.VOLT_MIN - new_offset)
141+
self.voltage_low = self.VOLT_MIN
142+
self.voltage_high = self.VOLT_MIN + self.amplitude
143+
else:
144+
self._update_volt_high_and_low(self.amplitude, new_offset)
145+
self.offset = new_offset
146+
147+
def _update_volt_high_and_low(self, new_volt, new_offs):
148+
"""Updates the value of voltage high and low for a given value of amplitude and offset.
149+
150+
:param new_volt: the value of the amplitude
151+
:param new_offs: the value of the offset
152+
"""
153+
self.offset = new_offs
154+
self.amplitude = new_volt
155+
self.voltage_high = new_offs + new_volt / 2
156+
self.voltage_low = new_offs - new_volt / 2
157+
158+
def get_output(self):
159+
return ["OFF", "ON"].index(self.output)
160+
161+
def get_range_auto(self):
162+
possible_ranges = ["OFF", "ON", "ONCE"]
163+
return possible_ranges.index(self.range_auto)
164+
165+
def set_function(self, new_function):
166+
self.function = new_function
167+
self.frequency = self.limit(
168+
self.frequency, self.FREQ_MINS[new_function], self.FREQ_MAXS[new_function]
169+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .stream_interface import AG33220AStreamInterface
2+
3+
__all__ = ["AG33220AStreamInterface"]

0 commit comments

Comments
 (0)