From 9f566296127e34c78deb2cb4e1648190a7d13305 Mon Sep 17 00:00:00 2001 From: Benedikt Moneke <67148916+bmoneke@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:52:58 +0200 Subject: [PATCH 1/6] Add pingUnit to ps4000a. --- picoscope/ps4000a.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/picoscope/ps4000a.py b/picoscope/ps4000a.py index 57d4507..b0322f8 100644 --- a/picoscope/ps4000a.py +++ b/picoscope/ps4000a.py @@ -454,6 +454,10 @@ def _lowLevelSetDataBufferBulk(self, channel, data, segmentIndex, self._lowLevelSetDataBuffer(channel, data, downSampleMode, segmentIndex) + def _lowLevelPingUnit(self): + """Check connection to picoscope and return the error.""" + return self.lib.ps4000aPingUnit(c_int16(self.handle)) + #################################################################### # Untested functions below # # # From ee9864de04786db0b3dff7a08374db913e1f5637 Mon Sep 17 00:00:00 2001 From: Benedikt Moneke Date: Tue, 3 Aug 2021 17:02:51 +0200 Subject: [PATCH 2/6] Fix getTimeBaseNum and getTimestepFromTimebase for the 4824A model. This model was not yet present. --- picoscope/ps4000a.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/picoscope/ps4000a.py b/picoscope/ps4000a.py index b0322f8..187036a 100644 --- a/picoscope/ps4000a.py +++ b/picoscope/ps4000a.py @@ -289,27 +289,29 @@ def _lowLevelIsReady(self): else: return False - def _lowLevelGetTimebase(self, tb, noSamples, oversample, segmentIndex): - """Return (timeIntervalSeconds, maxSamples).""" + def _lowLevelGetTimebase(self, timebase, noSamples, oversample, segmentIndex): + """Return (timeIntervalSeconds, maxSamples) for a given `timebase` number.""" maxSamples = c_int32() - sampleRate = c_float() + timeIntervalSeconds = c_float() - m = self.lib.ps4000aGetTimebase2(c_int16(self.handle), c_uint32(tb), - c_int32(noSamples), byref(sampleRate), + m = self.lib.ps4000aGetTimebase2(c_int16(self.handle), c_uint32(timebase), + c_int32(noSamples), byref(timeIntervalSeconds), byref(maxSamples), c_uint32(segmentIndex)) self.checkResult(m) - return (sampleRate.value / 1.0E9, maxSamples.value) + return (timeIntervalSeconds.value / 1.0E9, maxSamples.value) def getTimeBaseNum(self, sampleTimeS): - """ Convert the sample interval (float of seconds) to the - corresponding integer timebase value as defined by the API. - See "Timebases" section of the PS4000a programmers guide + """ + Convert `sampleTimeS` in s to the integer timebase number. + + See "Timebases" section of the PS4000a programmer's guide for more information. """ if self.model == '4828': + # TODO does a model 4828 exist? maxSampleTime = (((2 ** 32 - 1) + 1) / 8E7) if sampleTimeS <= 12.5E-9: @@ -337,6 +339,14 @@ def getTimeBaseNum(self, sampleTimeS): timebase = math.floor((sampleTimeS * 5.0E7) + 2) + elif self.model.startswith('4824'): + maxSampleTime = (((2 ** 32 - 1) + 1) / 8E7) + + if sampleTimeS > maxSampleTime: + sampleTimeS = maxSampleTime + timebase = math.floor(sampleTimeS * 8e7 - 1) + timebase = max(0, timebase) + else: # The original case from non "A" series warnings.warn("The model PS4000a you are using may not be " "fully supported", stacklevel=2) @@ -352,13 +362,11 @@ def getTimeBaseNum(self, sampleTimeS): timebase = math.floor((sampleTimeS * 2e7) + 1) - # is this cast needed? - timebase = int(timebase) return timebase def getTimestepFromTimebase(self, timebase): - """Return timebase to sampletime as seconds.""" - if self.model == '4828': + """Convert `timebase` index to sampletime in seconds.""" + if self.model == '4828' or self.model.startswith('4824'): dt = (timebase + 1) / 8.0E7 elif self.model == '4444': if timebase < 3: From 60a04278ab2a7d4e3bbfa05a3e215d3f68a6fee6 Mon Sep 17 00:00:00 2001 From: Benedikt Moneke <67148916+bmoneke@users.noreply.github.com> Date: Wed, 4 Aug 2021 01:27:42 +0200 Subject: [PATCH 3/6] Fix open with a serial number, see #169. --- picoscope/ps4000a.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/picoscope/ps4000a.py b/picoscope/ps4000a.py index 187036a..70838e4 100644 --- a/picoscope/ps4000a.py +++ b/picoscope/ps4000a.py @@ -143,7 +143,7 @@ def __init__(self, serialNumber=None, connect=True): def _lowLevelOpenUnit(self, sn): c_handle = c_int16() if sn is not None: - serialNullTermStr = create_string_buffer(str(sn)) + serialNullTermStr = create_string_buffer(bytes(sn, encoding='utf-8')) else: serialNullTermStr = None # Passing None is the same as passing NULL @@ -166,7 +166,7 @@ def _lowLevelOpenUnit(self, sn): def _lowLevelOpenUnitAsync(self, sn): c_status = c_int16() if sn is not None: - serialNullTermStr = create_string_buffer(sn) + serialNullTermStr = create_string_buffer(bytes(sn, encoding='utf-8')) else: serialNullTermStr = None From 636131612f33e96c804f53526b07fc8b28e1c22e Mon Sep 17 00:00:00 2001 From: Benedikt Moneke <67148916+bmoneke@users.noreply.github.com> Date: Thu, 5 Aug 2021 09:08:17 +0200 Subject: [PATCH 4/6] Adjust line length. Line lengths adjusted to be not more than 79 chars. OpenAsyncProgress stores the model version, if open has terminated. Otherwise self.model would not have been set, if openAsync is used. --- picoscope/ps4000a.py | 54 ++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/picoscope/ps4000a.py b/picoscope/ps4000a.py index 70838e4..95e22f7 100644 --- a/picoscope/ps4000a.py +++ b/picoscope/ps4000a.py @@ -140,14 +140,14 @@ def __init__(self, serialNumber=None, connect=True): super(PS4000a, self).__init__(serialNumber, connect) - def _lowLevelOpenUnit(self, sn): + def _lowLevelOpenUnit(self, serial): c_handle = c_int16() - if sn is not None: - serialNullTermStr = create_string_buffer(bytes(sn, encoding='utf-8')) + if serial is not None: + serialStr = create_string_buffer(bytes(serial, encoding='utf-8')) else: - serialNullTermStr = None + serialStr = None # Passing None is the same as passing NULL - m = self.lib.ps4000aOpenUnit(byref(c_handle), serialNullTermStr) + m = self.lib.ps4000aOpenUnit(byref(c_handle), serialStr) self.handle = c_handle.value # This will check if the power supply is not connected @@ -163,15 +163,15 @@ def _lowLevelOpenUnit(self, sn): self.model = self.getUnitInfo('VariantInfo') - def _lowLevelOpenUnitAsync(self, sn): + def _lowLevelOpenUnitAsync(self, serial): c_status = c_int16() - if sn is not None: - serialNullTermStr = create_string_buffer(bytes(sn, encoding='utf-8')) + if serial is not None: + serialStr = create_string_buffer(bytes(serial, encoding='utf-8')) else: - serialNullTermStr = None + serialStr = None # Passing None is the same as passing NULL - m = self.lib.ps4000aOpenUnitAsync(byref(c_status), serialNullTermStr) + m = self.lib.ps4000aOpenUnitAsync(byref(c_status), serialStr) self.checkResult(m) return c_status.value @@ -188,6 +188,7 @@ def _lowLevelOpenUnitProgress(self): if complete.value != 0: self.handle = handle.value + self.model = self.getUnitInfo('VariantInfo') # if we only wanted to return one value, we could do somethign like # progressPercent = progressPercent * (1 - 0.1 * complete) @@ -289,13 +290,35 @@ def _lowLevelIsReady(self): else: return False - def _lowLevelGetTimebase(self, timebase, noSamples, oversample, segmentIndex): - """Return (timeIntervalSeconds, maxSamples) for a given `timebase` number.""" + def _lowLevelGetTimebase(self, timebase, noSamples, oversample, + segmentIndex): + """ + Calculate the sampling interval and maximum number of samples. + + timebase + Number of the selected timebase. + noSamples + Number of required samples. + oversample + Nnot used. + segmentIndex + Index of the segment to save samples in + + Return + ------- + timeIntervalSeconds : float + Time interval between two samples in s. + maxSamples : int + maximum number of samples available depending on channels + and timebase chosen. + """ maxSamples = c_int32() timeIntervalSeconds = c_float() - m = self.lib.ps4000aGetTimebase2(c_int16(self.handle), c_uint32(timebase), - c_int32(noSamples), byref(timeIntervalSeconds), + m = self.lib.ps4000aGetTimebase2(c_int16(self.handle), + c_uint32(timebase), + c_int32(noSamples), + byref(timeIntervalSeconds), byref(maxSamples), c_uint32(segmentIndex)) self.checkResult(m) @@ -391,9 +414,6 @@ def _lowLevelSetDataBuffer(self, channel, data, downSampleMode, Be sure to call _lowLevelClearDataBuffer when you are done with the data array or else subsequent calls to GetValue will still use the same array. - - segmentIndex is unused, but required by other versions of the API - (eg PS5000a) """ dataPtr = data.ctypes.data_as(POINTER(c_int16)) numSamples = len(data) From 27b6c5d89a88462c7786881071041d0621cc000f Mon Sep 17 00:00:00 2001 From: Benedikt Moneke <67148916+bmoneke@users.noreply.github.com> Date: Mon, 9 Aug 2021 15:35:53 +0200 Subject: [PATCH 5/6] Add Signal Generator enumerations. --- picoscope/ps4000a.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/picoscope/ps4000a.py b/picoscope/ps4000a.py index 95e22f7..29e3db6 100644 --- a/picoscope/ps4000a.py +++ b/picoscope/ps4000a.py @@ -117,6 +117,12 @@ class PS4000a(_PicoscopeBase): "milliseconds": 4, "seconds": 5} + SIGGEN_TRIGGER_TYPES = {"Rising": 0, "Falling": 1, + "GateHigh": 2, "GateLow": 3} + + SIGGEN_TRIGGER_SOURCES = {"None": 0, "ScopeTrig": 1, + "AuxIn": 2, "ExtIn": 3, "SoftTrig": 4} + def __init__(self, serialNumber=None, connect=True): """Load DLLs.""" self.handle = None From 5ce4050c93508794ca5b03446f40f4af9d344d4c Mon Sep 17 00:00:00 2001 From: Benedikt Moneke <67148916+bmoneke@users.noreply.github.com> Date: Wed, 11 Aug 2021 10:05:25 +0200 Subject: [PATCH 6/6] Changed serial to serialNumber. --- picoscope/ps4000a.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/picoscope/ps4000a.py b/picoscope/ps4000a.py index 29e3db6..713a3a2 100644 --- a/picoscope/ps4000a.py +++ b/picoscope/ps4000a.py @@ -146,14 +146,15 @@ def __init__(self, serialNumber=None, connect=True): super(PS4000a, self).__init__(serialNumber, connect) - def _lowLevelOpenUnit(self, serial): + def _lowLevelOpenUnit(self, serialNumber): c_handle = c_int16() - if serial is not None: - serialStr = create_string_buffer(bytes(serial, encoding='utf-8')) + if serialNumber is not None: + serialNumberStr = create_string_buffer(bytes(serialNumber, + encoding='utf-8')) else: - serialStr = None + serialNumberStr = None # Passing None is the same as passing NULL - m = self.lib.ps4000aOpenUnit(byref(c_handle), serialStr) + m = self.lib.ps4000aOpenUnit(byref(c_handle), serialNumberStr) self.handle = c_handle.value # This will check if the power supply is not connected @@ -169,17 +170,18 @@ def _lowLevelOpenUnit(self, serial): self.model = self.getUnitInfo('VariantInfo') - def _lowLevelOpenUnitAsync(self, serial): + def _lowLevelOpenUnitAsync(self, serialNumber): c_status = c_int16() - if serial is not None: - serialStr = create_string_buffer(bytes(serial, encoding='utf-8')) + if serialNumber is not None: + serialNumberStr = create_string_buffer(bytes(serialNumber, + encoding='utf-8')) else: - serialStr = None - + serialNumberStr = None # Passing None is the same as passing NULL - m = self.lib.ps4000aOpenUnitAsync(byref(c_status), serialStr) + m = self.lib.ps4000aOpenUnitAsync(byref(c_status), serialNumberStr) self.checkResult(m) + # Set the model after completion in _lowLevelOpenUnitProgress. return c_status.value def _lowLevelOpenUnitProgress(self):