From 456ef399b63cd6010043d17a039bd9c33c69f82b Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Sat, 4 Jun 2022 16:52:07 +0200 Subject: Added workaround and debug details for setFrequency issue --- lab_control/jds6600.py | 22 +++++++++------ lab_control/test/jds6600_test.py | 21 +++++++++++++- lab_control/test/mock_jds6600_device.py | 50 ++++++++++++++++++++++----------- 3 files changed, 67 insertions(+), 26 deletions(-) (limited to 'lab_control') 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 + -- cgit v1.2.3