Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
22ba8ba
Rename plankton_emulators to lewis_emulators because framework name h…
Jan 6, 2017
6f425de
Update __init__.py
Jun 1, 2017
966314a
Merge pull request #17 from ISISComputingGroup/Ticket2371_EOL_fixes
FreddieAkeroyd Jun 2, 2017
91fdfb6
Tidied up the formatting for a lot of files
Jun 8, 2017
698b0ed
Merge pull request #18 from ISISComputingGroup/Ticket2379_Create_TPG2…
Jun 8, 2017
815d310
Pin emulators to latest version
Sep 25, 2017
f554372
Upgrade Lewis
davidkeymer Mar 23, 2018
45128f5
Update lewis_versions.py
esouthren Apr 3, 2018
54bf02f
Merge pull request #55 from ISISComputingGroup/Ticket2386_Upgrade_Lewis
esouthren Apr 3, 2018
1a874b3
Changed module name and updated emulator to pass temp test.
Jun 1, 2018
59fbcd5
Re-add lost init file, with comment saying do not delete.
Tom-Willemsen Jun 15, 2018
4994dc1
Add device to test framework
SophieKSTFC May 21, 2019
d27c2a8
Add template emulator
SophieKSTFC May 21, 2019
6dc8d94
Started testing emulator
SophieKSTFC May 22, 2019
a3cd557
Started building emulator
SophieKSTFC May 22, 2019
0aa12b7
Added additional features
SophieKSTFC May 24, 2019
1014e17
added additional tests
SophieKSTFC May 24, 2019
b8e5a5e
amended emulator to respond as the device does to error status requests
SophieKSTFC May 28, 2019
891a1e9
added additional tests
SophieKSTFC May 28, 2019
1c2cc9e
Added additional logic for switching to M CC
SophieKSTFC May 30, 2019
e70e3c9
additional tests for mode switching
SophieKSTFC May 30, 2019
07f277e
Added error status logic, ERR gets reset once it has been checked
SophieKSTFC Jun 4, 2019
9494699
amended tests
SophieKSTFC Jun 4, 2019
433e796
Amended tests to correlate with new capitalisation
SophieKSTFC Jun 24, 2019
2959325
Added the reset command and capitalised commands
SophieKSTFC Jun 24, 2019
ffc450b
Amended tests for new funtionality
SophieKSTFC Jun 25, 2019
e6da0dd
Amended mode logic to calculate voltage dynamically
SophieKSTFC Jun 25, 2019
18a246e
Amended tests to reflect the changes to the ERROR DB record, now only…
SophieKSTFC Jun 26, 2019
f18f140
Updated tests
Jul 8, 2019
5064a47
Added IOC macro's to test cases
Jul 8, 2019
0a2080c
Updated lewis version
DominicOram Sep 25, 2019
b11338b
Merge pull request #54 from ISISComputingGroup/Ticket4775_upgrade_lew…
Tom-Willemsen Sep 25, 2019
6bd44ec
renamed to cryogenic_sms/CRYOSMS
LilithCole Oct 15, 2019
325f5da
merge master
LilithCole Oct 15, 2019
f88ab88
Updated lewis version to 1.2.2
DominicOram Jun 1, 2020
7239040
Updated a number of imports, python3 syntax changes and minor PEP8 vi…
Sep 16, 2020
8fe914d
Fixed variable name for lewis version number
Sep 16, 2020
4a85601
Merge pull request #87 from ISISComputingGroup/Ticket4889_convert_dev…
rerpha Sep 24, 2020
68a1cef
Updated to use latest lewis version and convert strings correctly
DominicOram Nov 10, 2020
647c803
Update lewis version
DominicOram Nov 30, 2020
a1ef409
Add tests for TTIEX355P ioc
Tom-Willemsen Jan 14, 2021
6a0502c
ttiex355p: Add minimum to current and voltage range
JamesKingWork Apr 15, 2021
3bf8768
Refactor to use ttiex355p emulator - which is mostly subclassing the …
JamesKingWork May 19, 2021
72ec98c
Merge pull request #114 from ISISComputingGroup/Ticket6397_thurlby_range
DominicOram May 24, 2021
272bde3
Moved utils into lewis itself
DominicOram Jun 10, 2021
9b0ba48
Merge branch 'master' of C:/Instrument/Dev/EPICS-IOC_Test_Framework i…
Apr 22, 2022
af36083
Merge branch 'master' of C:/Instrument/Dev/EPICS-DeviceEmulator into …
Apr 22, 2022
e77f42a
Moved system tests to support module
Apr 22, 2022
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ relPaths.sh
/doc/
*_info_positions.req
*_info_settings.req
__pycache__/
*.py[cod]
*$py.class
test-reports/
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ iocBoot_DEPEND_DIRS += $(filter %App,$(DIRS))
# Add any additional dependency rules here:

include $(TOP)/configure/RULES_TOP


ioctests:
.\system_tests\run_tests.bat
Empty file added system_tests/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions system_tests/lewis_emulators/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# DO NOT DELETE THIS FILE - LEWIS FRAMEWORK REQUIRES THE DIRECTORY TO BE IMPORTABLE
from __future__ import absolute_import
2 changes: 2 additions & 0 deletions system_tests/lewis_emulators/lewis_versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
LEWIS_1_3_0 = "1.3.0"
LEWIS_LATEST = LEWIS_1_3_0
5 changes: 5 additions & 0 deletions system_tests/lewis_emulators/tti355/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .device import SimulatedTti355
from ..lewis_versions import LEWIS_LATEST

framework_version = LEWIS_LATEST
__all__ = ['SimulatedTti355']
106 changes: 106 additions & 0 deletions system_tests/lewis_emulators/tti355/device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from collections import OrderedDict
from .states import DefaultState
from lewis.devices import StateMachineDevice
from random import random


class SimulatedTti355(StateMachineDevice):

def _initialize_data(self):
"""
Initialize all of the device's attributes.
"""
self.identity = "Thurlby Thandar,EL302P,0,v1.14"
self.voltage = 0.00
self.voltage_sp = 1.00
self.current = 0.00
self.current_limit_sp = 1.00
self.output_status = "OUT OFF"
self.output_mode = "M CV"
self.error = "ERR 0"
self._max_voltage = 35.0
self._max_current = 5.0
self.load_resistance = 10

def reset(self):
self._initialize_data()

def _get_state_handlers(self):
return {
'default': DefaultState(),
}

def _get_initial_state(self):
return 'default'

def _get_transition_handlers(self):
return OrderedDict([
])

def calculate_potential_current(self, voltage):
return voltage/self.load_resistance

def calculate_actual_voltage(self):
return self.get_current() * self.load_resistance

def voltage_within_limits(self, voltage):
return voltage <= self._max_voltage

def get_voltage(self):
if self.output_status == "OUT ON":
if self.output_mode == "M CI":
self.voltage = self.calculate_actual_voltage()
else:
self.voltage = self.voltage_sp + ((random()-0.5)/1000)
else:
self.voltage = ((random()-0.5)/1000)
return self.voltage

def set_voltage_sp(self, voltage):
voltage = round(float(voltage), 2)
if not self.voltage_within_limits(voltage):
self.error = "ERR 2"
else:
self.voltage_sp = voltage
if self.calculate_potential_current(voltage) > self.current_limit_sp and self.output_status == "OUT ON":
self.output_mode = "M CI"

def current_within_limits(self, current):
return current <= self._max_current

def get_current(self):
if self.output_status == "OUT ON" and self.output_mode == "M CI":
self.current = self.current_limit_sp + ((random()-0.5)/1000)
else:
self.current = ((random()-0.5)/1000)
return self.current

def set_current_limit_sp(self, current):
current = round(float(current), 2)
if not self.current_within_limits(current):
self.error = "ERR 2"
else:
self.current_limit_sp = current

def set_output_status(self, status):
if status == "ON":
self.output_status = "OUT ON"
elif status == "OFF":
self.output_status = "OUT OFF"
self.reset()

def get_output_status(self):
return self.output_status

def get_output_mode(self):
return self.output_mode

def get_error_status(self):
if self.error == "ERR 1":
self.error = "ERR 0"
return "ERR 1"
elif self.error == "ERR 2":
self.error = "ERR 0"
return "ERR 2"
else:
return self.error
3 changes: 3 additions & 0 deletions system_tests/lewis_emulators/tti355/interfaces/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .stream_interface import Tti355StreamInterface

__all__ = ['Tti355StreamInterface']
85 changes: 85 additions & 0 deletions system_tests/lewis_emulators/tti355/interfaces/stream_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from lewis.adapters.stream import StreamInterface
from lewis.utils.command_builder import CmdBuilder


class Tti355StreamInterface(StreamInterface):

in_terminator = "\n"
out_terminator = "\r\n"

def __init__(self):

super(Tti355StreamInterface, self).__init__()

# Commands that we expect via serial during normal operation
self.commands = {
CmdBuilder(self.get_identity).escape("*IDN?").eos().build(),
CmdBuilder(self.reset).escape("*RST").eos().build(),
CmdBuilder(self.get_voltage_sp).escape("V?").eos().build(),
CmdBuilder(self.set_voltage_sp).escape("V ").float().eos().build(),
CmdBuilder(self.get_voltage).escape("VO?").eos().build(),

CmdBuilder(self.get_current_sp).escape("I?").eos().build(),
CmdBuilder(self.set_current_limit_sp).escape("I ").float().eos().build(),
CmdBuilder(self.get_current).escape("IO?").eos().build(),

CmdBuilder(self.get_outputstatus).escape("OUT?").eos().build(),
CmdBuilder(self.set_outputstatus_on).escape("ON").eos().build(),
CmdBuilder(self.set_outputstatus_off).escape("OFF").eos().build(),

CmdBuilder(self.get_output_mode).escape("M?").eos().build(),
CmdBuilder(self.get_error_status).escape("ERR?").eos().build(),

}

def handle_error(self, request, error):
err_string = "command was: {}, error was: {}: {}\n".format(request, error.__class__.__name__, error)
print(err_string)
self.log.error(err_string)
return err_string

def reset(self):
self.device.reset()
return self.out_terminator

def get_voltage(self):
volt = self.device.get_voltage()
return "V{:.2f}".format(volt)

def get_voltage_sp(self):
return "V{:.2f}".format(self.device.voltage_sp)

def set_voltage_sp(self, voltage_sp):
self.device.set_voltage_sp(float(voltage_sp))
return self.out_terminator

def get_current(self):
current = self.device.get_current()
return "I{:.2f}".format(current)

def get_current_sp(self):
return "I{:.2f}".format(self.device.current_limit_sp)

def set_current_limit_sp(self, current_limit_sp):
self.device.set_current_limit_sp(float(current_limit_sp))
return self.out_terminator

def get_outputstatus(self):
return self.device.get_output_status()

def set_outputstatus_on(self):
self.device.set_output_status("ON")
return self.out_terminator

def set_outputstatus_off(self):
self.device.set_output_status("OFF")
return self.out_terminator

def get_output_mode(self):
return self.device.get_output_mode()

def get_error_status(self):
return self.device.get_error_status()

def get_identity(self):
return self.device.identity
5 changes: 5 additions & 0 deletions system_tests/lewis_emulators/tti355/states.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lewis.core.statemachine import State


class DefaultState(State):
pass
10 changes: 10 additions & 0 deletions system_tests/run_tests.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@echo off
setlocal
REM Run this directory's tests using the IOC Testing Framework

call "%~dp0..\..\..\..\config_env.bat"

REM Command line arguments always passed to the test script
SET ARGS=--test_and_emulator %~dp0
call %PYTHON3% -u "%EPICS_KIT_ROOT%\support\IocTestFramework\master\run_tests.py" %ARGS% %*
IF %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
Empty file added system_tests/tests/__init__.py
Empty file.
78 changes: 78 additions & 0 deletions system_tests/tests/tti355.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import unittest
from parameterized import parameterized

from common_tests.tti_common import TtiCommon
from utils.channel_access import ChannelAccess
from utils.ioc_launcher import get_default_ioc_dir
from utils.test_modes import TestModes
from utils.testing import get_running_lewis_and_ioc, skip_if_recsim


DEVICE_PREFIX = "TTI355_01"
DEVICE_NAME = "tti355"

VOLT_LOW_LIMIT = 0.0
VOLT_HIGH_LIMIT = 35.0
CURR_LOW_LIMIT = 0.01
CURR_HIGH_LIMIT = 5.0

IOCS = [
{
"name": DEVICE_PREFIX,
"directory": get_default_ioc_dir("TTI355"),
"macros": {
"MIN_VOLT": VOLT_LOW_LIMIT,
"MAX_VOLT": VOLT_HIGH_LIMIT,
"MIN_CURR": CURR_LOW_LIMIT,
"MAX_CURR": CURR_HIGH_LIMIT,
},
"emulator": DEVICE_NAME,
},
]


TEST_MODES = [TestModes.RECSIM, TestModes.DEVSIM]


class Tti355Tests(TtiCommon, unittest.TestCase):
"""
Tests for the Tti355 IOC.
"""
def setUp(self):
self._lewis, self._ioc = get_running_lewis_and_ioc(DEVICE_NAME, DEVICE_PREFIX)
self.ca = ChannelAccess(device_prefix=DEVICE_PREFIX)
self._lewis.backdoor_run_function_on_device("reset")

def get_on_state_name(self):
return "ON"

def get_off_state_name(self):
return "OFF"

@parameterized.expand([
("lt_low_limit", VOLT_LOW_LIMIT-1.0, "low_limit", VOLT_LOW_LIMIT),
("gt_high_limit", VOLT_HIGH_LIMIT+1, "high_limit", VOLT_HIGH_LIMIT)])
@skip_if_recsim("Behaviour cannot be simulated in Recsim")
def test_WHEN_voltage_setpoint_is_set_outside_max_limits_THEN_setpoint_within(self, case, case_value, limit, limit_value):
self.ca.set_pv_value("VOLTAGE:SP", case_value)
self.ca.assert_that_pv_is("VOLTAGE:SP", limit_value)

@parameterized.expand([
("lt_low_limit", CURR_LOW_LIMIT-1, "low_limit", CURR_LOW_LIMIT),
("gt_high_limit", CURR_HIGH_LIMIT+1, "high_limit", CURR_HIGH_LIMIT)])
@skip_if_recsim("Behaviour cannot be simulated in Recsim")
def test_WHEN_voltage_setpoint_is_set_outside_max_limits_THEN_setpoint_within(self, case, case_value, limit, limit_value):
self.ca.set_pv_value("CURRENT:SP", case_value)
self.ca.assert_that_pv_is("CURRENT:SP", limit_value)

@skip_if_recsim("Behaviour cannot be simulated in Recsim")
def test_WHEN_identity_requested_THEN_correct_identity_returned(self):
expected_identity = "Thurlby Thandar,EL302P,0,v1.14"
self.ca.assert_that_pv_is("IDENT", expected_identity)

@skip_if_recsim("Behaviour cannot be simulated in Recsim")
def test_WHEN_ioc_in_error_state_2_THEN_correct_error_state_returned(self):
expected_value = "Cmd outside limits"
self._lewis.backdoor_set_on_device("error", "ERR 2")
self.ca.set_pv_value("ERROR.PROC", 1)
self.ca.assert_that_pv_is("ERROR", expected_value)