From ca601fd42c2a23723dc76fbf1cca7ac680ea16c2 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Aug 2024 11:24:12 +0300 Subject: [PATCH 1/7] ad7606: oversampling attribute are _get_iio_dev_attr type With the upstream Linux version, the oversampling, oversampling_ratio attributes are available at device level. _get_iio_attr() is used for accessing channel attributes. Signed-off-by: Alexandru Ardelean --- adi/ad7606.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adi/ad7606.py b/adi/ad7606.py index 61f593fa2..b9d8b7720 100644 --- a/adi/ad7606.py +++ b/adi/ad7606.py @@ -70,16 +70,16 @@ def range_available(self): @property def oversampling_ratio(self): """AD7606 oversampling_ratio""" - return self._get_iio_attr(self.name, "oversampling_ratio", False) + return self._get_iio_dev_attr("oversampling_ratio") @oversampling_ratio.setter def oversampling_ratio(self, value): - self._get_iio_attr(self.name, "oversampling_ratio", False, value) + self._set_iio_dev_attr("oversampling_ratio", value) @property def oversampling_ratio_available(self): """AD7606 channel oversampling_ratio_available""" - return self._get_iio_attr(self.name, "oversampling_ratio_available", False) + return self._get_iio_dev_attr("oversampling_ratio_available") class _channel(attribute): """AD7606 channel""" From 14bd599b1f5d6319b223b672efcfd99b3ad8f4a4 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Aug 2024 11:27:45 +0300 Subject: [PATCH 2/7] ad7606: remove non-existing range attributes There seems to be a confusion between scale and range. In the case of AD7606, the range (specified in the datasheet) determines the scale of the device (or the channel in some cases). Signed-off-by: Alexandru Ardelean --- adi/ad7606.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/adi/ad7606.py b/adi/ad7606.py index b9d8b7720..871f89e70 100644 --- a/adi/ad7606.py +++ b/adi/ad7606.py @@ -62,11 +62,6 @@ def scale_available(self): """Provides all available scale settings for the AD7606 channels""" return self._get_iio_attr(self.channel[0].name, "scale_available", False) - @property - def range_available(self): - """Provides all available range settings for the AD7606 channels""" - return self._get_iio_attr(self.channel[0].name, "range_available", False) - @property def oversampling_ratio(self): """AD7606 oversampling_ratio""" @@ -102,15 +97,6 @@ def scale(self): def scale(self, value): self._set_iio_attr(self.name, "scale", False, str(Decimal(value).real)) - @property - def range(self): - """AD7606 channel range""" - return self._get_iio_attr(self.name, "range", False) - - @range.setter - def range(self, value): - self._set_iio_attr(self.name, "range", False, str(Decimal(value).real)) - def to_volts(self, index, val): """Converts raw value to SI""" _scale = self.channel[index].scale From fa5b39d0a2bd830b9c49f56bc78f170003abff35 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Aug 2024 11:46:28 +0300 Subject: [PATCH 3/7] ad7606: init self._device_name member Signed-off-by: Alexandru Ardelean --- adi/ad7606.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/adi/ad7606.py b/adi/ad7606.py index 871f89e70..0a7ae9473 100644 --- a/adi/ad7606.py +++ b/adi/ad7606.py @@ -20,6 +20,8 @@ class ad7606(rx, context_manager): def __init__(self, uri="", device_name=""): + self._device_name = device_name + context_manager.__init__(self, uri, self._device_name) compatible_parts = [ From 3d01f082f6b551d42d8b359519f0f91a05138b84 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Aug 2024 11:53:23 +0300 Subject: [PATCH 4/7] ad7606: implement per-channel scale-available support The AD7606C-16 and AD7606C-18 support per-channel 'scale_availble' in SW mode. That is because each channel can be configured individually, to be bipolar-differential, bipolar-single-ended or unipolar-single-ended. Depending on the above configuration, the available scales change. So, we need to tweak this per-channel. Since there isn't a way to detect SW mode, we use some 'try' blocks in Python. Signed-off-by: Alexandru Ardelean --- adi/ad7606.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/adi/ad7606.py b/adi/ad7606.py index 0a7ae9473..17599c81d 100644 --- a/adi/ad7606.py +++ b/adi/ad7606.py @@ -55,14 +55,28 @@ def __init__(self, uri="", device_name=""): for ch in self._ctrl.channels: name = ch._id self._rx_channel_names.append(name) - self.channel.append(self._channel(self._ctrl, name)) + self.channel.append(self._channel(self, name)) rx.__init__(self) + @property + def has_device_scale_available(self): + """Returns true if the 'scale_available' attribute is at device level. + For AD7606C-16 and AD7606C-18 in SW mode, this is available + at channel level. + """ + if self._device_name not in ["ad7606c-16", "ad7606c-18"]: + return False + try: + _ = self._get_iio_dev_attr("scale_available") + return True + except Exception: + return False + @property def scale_available(self): """Provides all available scale settings for the AD7606 channels""" - return self._get_iio_attr(self.channel[0].name, "scale_available", False) + return self._get_iio_dev_attr("scale_available") @property def oversampling_ratio(self): @@ -81,9 +95,10 @@ def oversampling_ratio_available(self): class _channel(attribute): """AD7606 channel""" - def __init__(self, ctrl, channel_name): + def __init__(self, dev, channel_name): self.name = channel_name - self._ctrl = ctrl + self._dev = dev + self._ctrl = dev._ctrl @property def raw(self): @@ -99,6 +114,15 @@ def scale(self): def scale(self, value): self._set_iio_attr(self.name, "scale", False, str(Decimal(value).real)) + @property + def scale_available(self): + """'scale_available' is available per channel on AD7606C-16 and AD7606C-18 in SW mode""" + # We can't detect SW mode, so we use a try block + try: + return self._get_iio_attr_str(self.name, "scale_available", False) + except Exception: + return self._dev.scale_available + def to_volts(self, index, val): """Converts raw value to SI""" _scale = self.channel[index].scale From 8a4dfe73beca09a9b78cdca376f4fc402223e17c Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Aug 2024 11:57:13 +0300 Subject: [PATCH 5/7] ad7606: rework to_volts() method to support np.int32 For AD7606C-18 especially, there will be 32-bit samples getting returned from the ADC. Signed-off-by: Alexandru Ardelean --- adi/ad7606.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adi/ad7606.py b/adi/ad7606.py index 17599c81d..d2b82a70d 100644 --- a/adi/ad7606.py +++ b/adi/ad7606.py @@ -127,12 +127,12 @@ def to_volts(self, index, val): """Converts raw value to SI""" _scale = self.channel[index].scale - ret = None + # ADC7606C-18 will return int32 samples from the driver + if isinstance(val, np.int32): + return val * _scale if isinstance(val, np.int16): - ret = val * _scale + return val * _scale if isinstance(val, np.ndarray): - ret = [x * _scale for x in val] - - return ret + return [x * _scale for x in val] From f0378b96f97f8f6b087732b4b71cd9086e080923 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Aug 2024 12:02:58 +0300 Subject: [PATCH 6/7] ad7606: don't add timestamp channel to channels array The soft timestamp channel is a special IIO channel. It's not an RX channel, so it hasn't any of the typically attributes (raw, scale, etc) like the other RX channels. So, just ignore it. Signed-off-by: Alexandru Ardelean --- adi/ad7606.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/adi/ad7606.py b/adi/ad7606.py index d2b82a70d..5278c9a44 100644 --- a/adi/ad7606.py +++ b/adi/ad7606.py @@ -54,6 +54,8 @@ def __init__(self, uri="", device_name=""): self.channel = [] for ch in self._ctrl.channels: name = ch._id + if (name == "timestamp"): + continue self._rx_channel_names.append(name) self.channel.append(self._channel(self, name)) From b54a3dc4eb59c4f0b1c3b3f7495e7678834fda9a Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 19 Aug 2024 12:10:29 +0300 Subject: [PATCH 7/7] ad7606: add handling in to_volts() method for 'int' and 'list' At least the 'raw' channel attribute returns int. So, 'ad7606.to_volts(0, channel0.raw)' won't work with checking for numpy types. Signed-off-by: Alexandru Ardelean --- adi/ad7606.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/adi/ad7606.py b/adi/ad7606.py index 5278c9a44..35e519cbf 100644 --- a/adi/ad7606.py +++ b/adi/ad7606.py @@ -129,6 +129,12 @@ def to_volts(self, index, val): """Converts raw value to SI""" _scale = self.channel[index].scale + if isinstance(val, int): + return val * _scale + + if isinstance(val, list): + return [x * _scale for x in val] + # ADC7606C-18 will return int32 samples from the driver if isinstance(val, np.int32): return val * _scale