summaryrefslogtreecommitdiffstats
path: root/lab_control
diff options
context:
space:
mode:
authorEddy Pedroni <eddy@0xf7.com>2022-06-04 16:52:07 +0200
committerEddy Pedroni <eddy@0xf7.com>2022-06-04 16:52:07 +0200
commit456ef399b63cd6010043d17a039bd9c33c69f82b (patch)
tree2d13461afb5abd137f15d40a23ddfd6e9d81e4cb /lab_control
parent1aec3bacaab2991121e0c00d147fd418cdbfbc17 (diff)
Added workaround and debug details for setFrequency issue
Diffstat (limited to 'lab_control')
-rw-r--r--lab_control/jds6600.py22
-rw-r--r--lab_control/test/jds6600_test.py21
-rw-r--r--lab_control/test/mock_jds6600_device.py50
3 files changed, 67 insertions, 26 deletions
diff --git a/lab_control/jds6600.py b/lab_control/jds6600.py
index 5ada6cf..4ab4955 100644
--- a/lab_control/jds6600.py
+++ b/lab_control/jds6600.py
@@ -41,10 +41,10 @@ class JDS6600(FunctionGenerator):
"""
self._port.close()
- def _queryOnOff(self) -> list[str, str]:
- # response format: ":r20=0,0."
- response = self._sendRequest("r20")
- return [response[5], response[7]]
+ def _query(self, opcode: str) -> list[str]:
+ # response format: ":{opcode}={v1},{v2}."
+ response = self._sendRequest(opcode)
+ return response[5:-1].split(",")
def _sendRequest(self, opcode: str, args: str="") -> str:
request = f":{opcode}={args}.\r\n"
@@ -55,14 +55,14 @@ class JDS6600(FunctionGenerator):
def setOn(self, channel: int) -> None:
_checkChannel(channel)
- state = self._queryOnOff()
+ state = self._query("r20")
state[channel - 1] = "1"
self._sendRequest("w20", f"{state[0]},{state[1]}")
def setOff(self, channel: int) -> None:
_checkChannel(channel)
- state = self._queryOnOff()
+ state = self._query("r20")
state[channel - 1] = "0"
self._sendRequest("w20", f"{state[0]},{state[1]}")
@@ -70,9 +70,15 @@ class JDS6600(FunctionGenerator):
_checkChannel(channel)
_checkArg(frequency, 0.0, 60e6)
- opcode = f"w{23 + channel - 1}"
+ opcode = 23 + channel - 1
arg = int(frequency * 100.0)
- self._sendRequest(opcode, str(arg))
+ self._sendRequest(f"w{opcode}", f"{arg},0")
+
+ # JDS6600 has been observed to sometimes incorrectly
+ # ignore the frequency and set to 0 instead
+ actual = self._query(f"r{opcode}")[0]
+ if actual != arg:
+ self._sendRequest(f"w{opcode}", f"{arg},0")
def setAmplitude(self, channel: int, amplitude: float) -> None:
_checkChannel(channel)
diff --git a/lab_control/test/jds6600_test.py b/lab_control/test/jds6600_test.py
index 817ccf4..59e2d33 100644
--- a/lab_control/test/jds6600_test.py
+++ b/lab_control/test/jds6600_test.py
@@ -17,7 +17,7 @@ def uut(mockDevice):
def checkNumericalParameter(testValues, writeValue, valueInMock):
for ch in JDS6600.AVAILABLE_CHANNELS:
- assert valueInMock(ch) == None
+ assert valueInMock(ch) is None
for value in testValues:
writeValue(ch, value)
@@ -75,3 +75,22 @@ def test_invalidChannel(uut):
with pytest.raises(AssertionError):
uut.setOff(ch)
+def test_setFrequencySingleFailure(uut, mockDevice):
+ testFrequency = 1000.0
+ testChannel = 1
+ assert mockDevice.getFrequency(testChannel) is None
+
+ mockDevice.injectFailures(1)
+ uut.setFrequency(testChannel, testFrequency)
+
+ assert mockDevice.getFrequency(testChannel) == testFrequency
+
+def test_setFrequencyMultipleFailures(uut, mockDevice):
+ testFrequency = 1000.0
+ testChannel = 1
+ assert mockDevice.getFrequency(testChannel) is None
+
+ mockDevice.injectFailures(2)
+ uut.setFrequency(testChannel, testFrequency)
+
+ assert mockDevice.getFrequency(testChannel) == 0.0
diff --git a/lab_control/test/mock_jds6600_device.py b/lab_control/test/mock_jds6600_device.py
index 979ec69..c027573 100644
--- a/lab_control/test/mock_jds6600_device.py
+++ b/lab_control/test/mock_jds6600_device.py
@@ -18,6 +18,8 @@ class MockJDS6600Device():
self._portName = os.ttyname(self._slave)
self._channels = [MockJDS6600Device.ChannelState() for i in [1, 2]]
+
+ self._injectedFailureCounter = 0
self._mainThread = threading.Thread(target=self._mainLoop)
self._mainThread.start()
@@ -44,37 +46,48 @@ class MockJDS6600Device():
function = int(m.group("function"))
args = m.group("args").split(",")
- if opcode == "w":
- # channel on/off
- if function == 20:
+ # channel on/off
+ if function == 20:
+ if opcode == "w":
self._channels[0].on = args[0] == "1"
self._channels[1].on = args[1] == "1"
+ return ":ok\r\n"
+ elif opcode == "r":
+ return f":r20={int(self._channels[0].on)},{int(self._channels[1].on)}.\r\n"
- # channel frequency
- elif function == 23 or function == 24:
+ # channel frequency
+ elif function == 23 or function == 24:
+ ch = function - 23
+ if opcode == "w":
# Actual device takes a second argument for scaling, here we ignore it and always use 0 (Hz)
- ch = function - 23
frequency = float(args[0]) / 100.0
- self._channels[ch].frequency = frequency
- # channel amplitude
- elif function == 25 or function == 26:
+ if self._injectedFailureCounter > 0:
+ self._channels[ch].frequency = 0.0
+ self._injectedFailureCounter -= 1
+ else:
+ self._channels[ch].frequency = frequency
+ return ":ok\r\n"
+ elif opcode == "r":
+ frequency = self._channels[ch].frequency
+ return f":r{function}={int(frequency)},0.\r\n"
+
+ # channel amplitude
+ elif function == 25 or function == 26:
+ if opcode == "w":
ch = function - 25
amplitude = float(args[0]) / 1000.0
self._channels[ch].amplitude = amplitude
+ return ":ok\r\n"
- # channel function shape
- elif function == 21 or function == 22:
+ # channel function shape
+ elif function == 21 or function == 22:
+ if opcode == "w":
ch = function - 21
shape = int(args[0])
self._channels[ch].function = shape
+ return ":ok\r\n"
- return ":ok\r\n"
-
- elif opcode == "r":
- if function == 20:
- return f":r20={int(self._channels[0].on)},{int(self._channels[1].on)}.\r\n"
-
# Unknown request format, no response
return None
@@ -109,3 +122,6 @@ class MockJDS6600Device():
def getFunction(self, ch: int) -> int:
return self._channels[ch - 1].function
+ def injectFailures(self, count: int) -> None:
+ self._injectedFailureCounter += count
+