From 3e95767db4f7dee79708dc07df83ab2d416404f0 Mon Sep 17 00:00:00 2001
From: Janani Sunil <janani.sunil@analog.com>
Date: Fri, 14 Jun 2024 09:29:30 +0530
Subject: [PATCH] adi:ad4170: Add support for ad4170

1. Add pyadi driver for ad4170 family
2. Add example script for data capture with ad4170
3. Add documentation

Signed-off-by: Janani Sunil <janani.sunil@analog.com>
---
 adi/__init__.py                   |  1 +
 adi/ad4170.py                     | 94 +++++++++++++++++++++++++++++++
 doc/source/devices/adi.ad4170.rst |  7 +++
 doc/source/devices/index.rst      |  1 +
 examples/ad4170_example.py        | 17 ++++++
 supported_parts.md                |  1 +
 test/emu/devices/ad4170.xml       |  1 +
 test/emu/hardware_map.yml         | 11 +++-
 test/test_ad4170.py               | 12 ++++
 9 files changed, 144 insertions(+), 1 deletion(-)
 create mode 100644 adi/ad4170.py
 create mode 100644 doc/source/devices/adi.ad4170.rst
 create mode 100644 examples/ad4170_example.py
 create mode 100644 test/emu/devices/ad4170.xml
 create mode 100644 test/test_ad4170.py

diff --git a/adi/__init__.py b/adi/__init__.py
index d2d4ff84f..86f43b091 100644
--- a/adi/__init__.py
+++ b/adi/__init__.py
@@ -14,6 +14,7 @@
 from adi.ad4020 import ad4000, ad4001, ad4002, ad4003, ad4020
 from adi.ad4110 import ad4110
 from adi.ad4130 import ad4130
+from adi.ad4170 import ad4170
 from adi.ad4630 import ad4630, adaq42xx
 from adi.ad4858 import ad4858
 from adi.ad5592r import ad5592r
diff --git a/adi/ad4170.py b/adi/ad4170.py
new file mode 100644
index 000000000..f7c87d67a
--- /dev/null
+++ b/adi/ad4170.py
@@ -0,0 +1,94 @@
+# Copyright (C) 2024 Analog Devices, Inc.
+#
+# SPDX short identifier: ADIBSD
+
+
+from decimal import Decimal
+
+import numpy as np
+from adi.attribute import attribute
+from adi.context_manager import context_manager
+from adi.rx_tx import rx
+
+
+class ad4170(rx, context_manager):
+    """ AD4170 ADC """
+
+    _complex_data = False
+    channels = []  # type: ignore
+    _device_name = ""
+
+    def __init__(self, uri="", device_name=""):
+
+        context_manager.__init__(self, uri, self._device_name)
+
+        compatible_parts = ["ad4170"]
+
+        self._ctrl = None
+
+        if not device_name:
+            device_name = compatible_parts[0]
+        else:
+            if device_name not in compatible_parts:
+                raise Exception("Not a compatible device: " + device_name)
+
+        # Select the device matching device_name as working device
+        for device in self._ctx.devices:
+            if device.name == device_name:
+                self._ctrl = device
+                self._rxadc = device
+                break
+
+        self.channels = []
+        for ch in self._ctrl.channels:
+            name = ch._id
+            self._rx_channel_names.append(name)
+            self.channels.append(self._channel(self._ctrl, name))
+
+        rx.__init__(self)
+
+    class _channel(attribute):
+        """AD4170 channel"""
+
+        def __init__(self, ctrl, channel_name):
+            self.name = channel_name
+            self._ctrl = ctrl
+
+        @property
+        def raw(self):
+            """AD4170 channel raw value"""
+            return self._get_iio_attr(self.name, "raw", False)
+
+        @property
+        def offset(self):
+            """AD4170 channel offset"""
+            return float(self._get_iio_attr_str(self.name, "offset", False))
+
+        @offset.setter
+        def offset(self, value):
+            self._set_iio_attr(self.name, "offset", False, str(Decimal(value).real))
+
+        @property
+        def scale(self):
+            """AD4170 channel scale"""
+            return float(self._get_iio_attr_str(self.name, "scale", False))
+
+        @scale.setter
+        def scale(self, value):
+            self._set_iio_attr(self.name, "scale", False, str(Decimal(value).real))
+
+    def to_volts(self, index, val):
+        """Converts raw value to SI
+            index - Channel index
+            val- Raw value """
+        _scale = self.channel[index].scale
+
+        ret = None
+
+        if isinstance(val, np.int16):
+            ret = val * _scale
+
+        if isinstance(val, np.ndarray):
+            ret = [x * _scale for x in val]
+
+        return ret
diff --git a/doc/source/devices/adi.ad4170.rst b/doc/source/devices/adi.ad4170.rst
new file mode 100644
index 000000000..b5b3ed3fd
--- /dev/null
+++ b/doc/source/devices/adi.ad4170.rst
@@ -0,0 +1,7 @@
+ad4170
+=================
+
+.. automodule:: adi.ad4170
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff --git a/doc/source/devices/index.rst b/doc/source/devices/index.rst
index b9451ab08..2b41e444f 100644
--- a/doc/source/devices/index.rst
+++ b/doc/source/devices/index.rst
@@ -13,6 +13,7 @@ Supported Devices
    adi.ad405x
    adi.ad4110
    adi.ad4130
+   adi.ad4170
    adi.ad4630
    adi.ad469x
    adi.ad5592r
diff --git a/examples/ad4170_example.py b/examples/ad4170_example.py
new file mode 100644
index 000000000..3c192ae28
--- /dev/null
+++ b/examples/ad4170_example.py
@@ -0,0 +1,17 @@
+# Copyright (C) 2024 Analog Devices, Inc.
+#
+# SPDX short identifier: ADIBSD
+
+import adi
+import numpy as np
+
+ad4170_dev = adi.ad4170("ip:analog")
+
+chn = 0
+ad4170_dev.rx_output_type = "SI"
+ad4170_dev.rx_enabled_channels = [chn]
+ad4170_dev.rx_buffer_size = 100
+
+data = ad4170_dev.rx()
+
+print(data)
diff --git a/supported_parts.md b/supported_parts.md
index 0ddfdb1c2..060665fd1 100644
--- a/supported_parts.md
+++ b/supported_parts.md
@@ -25,6 +25,7 @@
 - AD4115
 - AD4116
 - AD4134
+- AD4170
 - AD4630
 - AD4696
 - AD4697
diff --git a/test/emu/devices/ad4170.xml b/test/emu/devices/ad4170.xml
new file mode 100644
index 000000000..03bef190e
--- /dev/null
+++ b/test/emu/devices/ad4170.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><!DOCTYPE context [<!ELEMENT context (device | context-attribute)*><!ELEMENT context-attribute EMPTY><!ELEMENT device (channel | attribute | debug-attribute | buffer-attribute)*><!ELEMENT channel (scan-element?, attribute*)><!ELEMENT attribute EMPTY><!ELEMENT scan-element EMPTY><!ELEMENT debug-attribute EMPTY><!ELEMENT buffer-attribute EMPTY><!ATTLIST context name CDATA #REQUIRED description CDATA #IMPLIED><!ATTLIST context-attribute name CDATA #REQUIRED value CDATA #REQUIRED><!ATTLIST device id CDATA #REQUIRED name CDATA #IMPLIED><!ATTLIST channel id CDATA #REQUIRED type (input|output) #REQUIRED name CDATA #IMPLIED><!ATTLIST scan-element index CDATA #REQUIRED format CDATA #REQUIRED scale CDATA #IMPLIED><!ATTLIST attribute name CDATA #REQUIRED filename CDATA #IMPLIED value CDATA #IMPLIED><!ATTLIST debug-attribute name CDATA #REQUIRED value CDATA #IMPLIED><!ATTLIST buffer-attribute name CDATA #REQUIRED value CDATA #IMPLIED>]><context name="serial" description="no-OS/projects/NO_OS_PROJECT 0.1" ><context-attribute name="hw_carrier" value="SDP_K1" /><context-attribute name="hw_mezzanine" value="EVAL-AD4170-ARDZ" /><context-attribute name="hw_name" value="EVAL-AD4170-ARDZ" /><context-attribute name="uri" value="serial:/dev/ttyS0,230400,8n1n" /><context-attribute name="serial,port" value="/dev/ttyS0" /><context-attribute name="serial,description" value="ttyS0" /><device id="iio:device0" name="ad4170" ><channel id="voltage0" name="Chn0" type="input" ><scan-element index="0" format="le:s24/32&gt;&gt;0" /><attribute name="raw" filename="in_voltage0_raw" value="16749356" /><attribute name="scale" filename="in_voltage0_scale" value="0.0002980232" /><attribute name="offset" filename="in_voltage0_offset" value="-16777215" /><attribute name="internal_calibration" filename="in_voltage0_internal_calibration" value="NA" /><attribute name="system_calibration" filename="in_voltage0_system_calibration" value="NA" /><attribute name="filter" filename="in_voltage0_filter" value="sinc5_avg" /><attribute name="filter_available" filename="in_voltage0_filter_available" value="sinc5_avg sinc5 sinc3" /><attribute name="ref_select" filename="in_voltage0_ref_select" value="refout_avss" /><attribute name="ref_select_available" filename="in_voltage0_ref_select_available" value="refin1p_refin1m refin2p_refin2m refout_avss avdd_avss" /><attribute name="fs" filename="in_voltage0_fs" value="16" /></channel><channel id="voltage1" name="Chn1" type="input" ><scan-element index="1" format="le:s24/32&gt;&gt;0" /><attribute name="raw" filename="in_voltage1_raw" value="16777157" /><attribute name="scale" filename="in_voltage1_scale" value="0.0002980232" /><attribute name="offset" filename="in_voltage1_offset" value="-16777215" /><attribute name="internal_calibration" filename="in_voltage1_internal_calibration" value="NA" /><attribute name="system_calibration" filename="in_voltage1_system_calibration" value="NA" /><attribute name="filter" filename="in_voltage1_filter" value="sinc5_avg" /><attribute name="filter_available" filename="in_voltage1_filter_available" value="sinc5_avg sinc5 sinc3" /><attribute name="ref_select" filename="in_voltage1_ref_select" value="refout_avss" /><attribute name="ref_select_available" filename="in_voltage1_ref_select_available" value="refin1p_refin1m refin2p_refin2m refout_avss avdd_avss" /><attribute name="fs" filename="in_voltage1_fs" value="16" /></channel><channel id="voltage2" name="Chn2" type="input" ><scan-element index="2" format="le:s24/32&gt;&gt;0" /><attribute name="raw" filename="in_voltage2_raw" value="16777171" /><attribute name="scale" filename="in_voltage2_scale" value="0.0002980232" /><attribute name="offset" filename="in_voltage2_offset" value="-16777215" /><attribute name="internal_calibration" filename="in_voltage2_internal_calibration" value="NA" /><attribute name="system_calibration" filename="in_voltage2_system_calibration" value="NA" /><attribute name="filter" filename="in_voltage2_filter" value="sinc5_avg" /><attribute name="filter_available" filename="in_voltage2_filter_available" value="sinc5_avg sinc5 sinc3" /><attribute name="ref_select" filename="in_voltage2_ref_select" value="refout_avss" /><attribute name="ref_select_available" filename="in_voltage2_ref_select_available" value="refin1p_refin1m refin2p_refin2m refout_avss avdd_avss" /><attribute name="fs" filename="in_voltage2_fs" value="16" /></channel><channel id="voltage3" name="Chn3" type="input" ><scan-element index="3" format="le:s24/32&gt;&gt;0" /><attribute name="raw" filename="in_voltage3_raw" value="16777108" /><attribute name="scale" filename="in_voltage3_scale" value="0.0002980232" /><attribute name="offset" filename="in_voltage3_offset" value="-16777215" /><attribute name="internal_calibration" filename="in_voltage3_internal_calibration" value="NA" /><attribute name="system_calibration" filename="in_voltage3_system_calibration" value="NA" /><attribute name="filter" filename="in_voltage3_filter" value="sinc5_avg" /><attribute name="filter_available" filename="in_voltage3_filter_available" value="sinc5_avg sinc5 sinc3" /><attribute name="ref_select" filename="in_voltage3_ref_select" value="refout_avss" /><attribute name="ref_select_available" filename="in_voltage3_ref_select_available" value="refin1p_refin1m refin2p_refin2m refout_avss avdd_avss" /><attribute name="fs" filename="in_voltage3_fs" value="16" /></channel><attribute name="demo_config" value="User Default" /><attribute name="sampling_frequency" value="7812" /><attribute name="diagnostic_error_status" value="ERROR" /><attribute name="adc_mode_available" value="Continuous_Conversion Continuous_Conversion_FIR Continuous_Conversion_IIR Standby Power_Down Idle" /><attribute name="adc_mode" value="Standby" /><attribute name="filter_available" value="sinc5_avg sinc5 sinc3" /><attribute name="clock_ctrl" value="internal_osc" /><attribute name="clock_ctrl_available" value="internal_osc internal_osc_output external_osc external_xtal" /><debug-attribute name="direct_reg_access" value="16" /></device><device id="trigger0" name="ad4170_iio_trigger" ></device></context>
\ No newline at end of file
diff --git a/test/emu/hardware_map.yml b/test/emu/hardware_map.yml
index a2b0ba1c4..ce4f03655 100644
--- a/test/emu/hardware_map.yml
+++ b/test/emu/hardware_map.yml
@@ -600,4 +600,13 @@ ad7134:
       - data_devices:
         - iio:device0
   - pyadi_iio_class_support:
-      - ad7134
\ No newline at end of file
+      - ad7134
+      
+ad4170:
+ - ad4170
+ - pyadi_iio_class_support:
+     - ad4170
+ - emulate:
+     - filename: ad4170.xml
+     - data_devices:
+         - iio:device0
diff --git a/test/test_ad4170.py b/test/test_ad4170.py
new file mode 100644
index 000000000..0257525e8
--- /dev/null
+++ b/test/test_ad4170.py
@@ -0,0 +1,12 @@
+import pytest
+
+hardware = "ad4170"
+classname = "adi.ad4170"
+
+
+#########################################
+@pytest.mark.iio_hardware(hardware, True)
+@pytest.mark.parametrize("classname", [(classname)])
+@pytest.mark.parametrize("channel", [0])
+def test_ad4170_rx_data(test_dma_rx, iio_uri, classname, channel):
+    test_dma_rx(iio_uri, classname, channel)