From ac2e3da22d0c4bc673e67a4795693619515f097b Mon Sep 17 00:00:00 2001
From: rbudai <robert.budai@analog.com>
Date: Mon, 21 Oct 2024 10:23:50 +0300
Subject: [PATCH] Add support for adis16550 and adis16550w

Signed-off-by: rbudai <robert.budai@analog.com>
---
 adi/__init__.py                      |   1 +
 adi/adis16550.py                     | 473 +++++++++++++++++++++++++++
 doc/source/devices/adi.adis16550.rst |   8 +
 doc/source/devices/index.rst         |   1 +
 examples/adis16550_example.py        |  59 ++++
 supported_parts.md                   |   2 +
 test/emu/devices/adis16550.xml       | 149 +++++++++
 test/emu/hardware_map.yml            |   9 +
 test/test_adis16550.py               |  80 +++++
 9 files changed, 782 insertions(+)
 create mode 100644 adi/adis16550.py
 create mode 100644 doc/source/devices/adi.adis16550.rst
 create mode 100644 examples/adis16550_example.py
 create mode 100644 test/emu/devices/adis16550.xml
 create mode 100644 test/test_adis16550.py

diff --git a/adi/__init__.py b/adi/__init__.py
index bf1f21657..57dfd9ce8 100644
--- a/adi/__init__.py
+++ b/adi/__init__.py
@@ -73,6 +73,7 @@
     adis16547,
 )
 from adi.adis16507 import adis16507
+from adi.adis16550 import adis16550
 from adi.adl5240 import adl5240
 from adi.adl5960 import adl5960
 from adi.admv8818 import admv8818
diff --git a/adi/adis16550.py b/adi/adis16550.py
new file mode 100644
index 000000000..7c483dba4
--- /dev/null
+++ b/adi/adis16550.py
@@ -0,0 +1,473 @@
+# Copyright (C) 2019-2024 Analog Devices, Inc.
+#
+# SPDX short identifier: ADIBSD
+
+from adi.attribute import attribute
+from adi.context_manager import context_manager
+from adi.rx_tx import rx
+
+
+class adis16550(rx, context_manager):
+    _complex_data = False
+
+    _rx_channel_names = [
+        "anglvel_x",
+        "anglvel_y",
+        "anglvel_z",
+        "accel_x",
+        "accel_y",
+        "accel_z",
+        "temp0",
+        "deltaangl_x",
+        "deltaangl_y",
+        "deltaangl_z",
+        "deltavelocity_x",
+        "deltavelocity_y",
+        "deltavelocity_z",
+    ]
+
+    _device_name = ""
+
+    """Disable mapping of trigger to RX device."""
+    disable_trigger = False
+
+    def __init__(self, uri="", device_name=None, trigger_name=None):
+        context_manager.__init__(self, uri, self._device_name)
+
+        compatible_parts = ["adis16550", "adis16550w"]
+
+        if not device_name:
+            device_name = compatible_parts[0]
+
+        if device_name not in compatible_parts:
+            raise Exception(
+                "Not a compatible device:"
+                + str(device_name)
+                + ".Please select from:"
+                + str(compatible_parts)
+            )
+        else:
+            self._ctrl = self._ctx.find_device(device_name)
+            self._rxadc = self._ctx.find_device(device_name)
+            if not trigger_name:
+                trigger_name = device_name + "-dev0"
+
+        if self._ctrl is None:
+            print(
+                "No device found with device_name = "
+                + device_name
+                + ". Searching for a device found in the compatible list."
+            )
+            for i in compatible_parts:
+                self._ctrl = self._ctx.find_device(i)
+                self._rxadc = self._ctx.find_device(i)
+                if self._ctrl is not None:
+                    print("Found device = " + i + ". Will use this device instead.")
+                    break
+            if self._ctrl is None:
+                raise Exception("No compatible device found")
+
+        self.anglvel_x = self._anglvel_accel_channels(self._ctrl, "anglvel_x")
+        self.anglvel_y = self._anglvel_accel_channels(self._ctrl, "anglvel_y")
+        self.anglvel_z = self._anglvel_accel_channels(self._ctrl, "anglvel_z")
+        self.accel_x = self._anglvel_accel_channels(self._ctrl, "accel_x")
+        self.accel_y = self._anglvel_accel_channels(self._ctrl, "accel_y")
+        self.accel_z = self._anglvel_accel_channels(self._ctrl, "accel_z")
+        self.temp = self._temp_channel(self._ctrl, "temp0")
+        self.deltaangl_x = self._delta_channels(self._ctrl, "deltaangl_x")
+        self.deltaangl_y = self._delta_channels(self._ctrl, "deltaangl_y")
+        self.deltaangl_z = self._delta_channels(self._ctrl, "deltaangl_z")
+        self.deltavelocity_x = self._delta_channels(self._ctrl, "deltavelocity_x")
+        self.deltavelocity_y = self._delta_channels(self._ctrl, "deltavelocity_y")
+        self.deltavelocity_z = self._delta_channels(self._ctrl, "deltavelocity_z")
+
+        # Set default trigger
+        if not self.disable_trigger:
+            self._trigger = self._ctx.find_device(trigger_name)
+            self._rxadc._set_trigger(self._trigger)
+
+        rx.__init__(self)
+        self.rx_buffer_size = 16  # Make default buffer smaller
+
+    def __get_scaled_sensor(self, channel_name: str) -> float:
+        raw = self._get_iio_attr(channel_name, "raw", False)
+        scale = self._get_iio_attr(channel_name, "scale", False)
+
+        return raw * scale
+
+    def __get_scaled_sensor_temp(self, channel_name: str) -> float:
+        raw = self._get_iio_attr(channel_name, "raw", False)
+        scale = self._get_iio_attr(channel_name, "scale", False)
+        offset = self._get_iio_attr(channel_name, "offset", False)
+
+        return (raw + offset) * scale
+
+    def get_anglvel_x(self):
+        """Value returned in radians per second."""
+        return self.__get_scaled_sensor("anglvel_x")
+
+    anglvel_x_conv = property(get_anglvel_x, None)
+
+    def get_anglvel_y(self):
+        """Value returned in radians per second."""
+        return self.__get_scaled_sensor("anglvel_y")
+
+    anglvel_y_conv = property(get_anglvel_y, None)
+
+    def get_anglvel_z(self):
+        """Value returned in radians per second."""
+        return self.__get_scaled_sensor("anglvel_z")
+
+    anglvel_z_conv = property(get_anglvel_z, None)
+
+    def get_accel_x(self):
+        """Value returned in meters per squared second."""
+        return self.__get_scaled_sensor("accel_x")
+
+    accel_x_conv = property(get_accel_x, None)
+
+    def get_accel_y(self):
+        """Value returned in meters per squared second."""
+        return self.__get_scaled_sensor("accel_y")
+
+    accel_y_conv = property(get_accel_y, None)
+
+    def get_accel_z(self):
+        """Value returned in meters per squared second."""
+        return self.__get_scaled_sensor("accel_z")
+
+    accel_z_conv = property(get_accel_z, None)
+
+    def get_temp(self):
+        """Value returned in millidegrees Celsius."""
+        return self.__get_scaled_sensor_temp("temp0")
+
+    temp_conv = property(get_temp, None)
+
+    def get_deltaangl_x(self):
+        """Value returned in radians."""
+        return self.__get_scaled_sensor("deltaangl_x")
+
+    deltaangl_x_conv = property(get_deltaangl_x, None)
+
+    def get_deltaangl_y(self):
+        """Value returned in radians."""
+        return self.__get_scaled_sensor("deltaangl_y")
+
+    deltaangl_y_conv = property(get_deltaangl_y, None)
+
+    def get_deltaangl_z(self):
+        """Value returned in radians."""
+        return self.__get_scaled_sensor("deltaangl_z")
+
+    deltaangl_z_conv = property(get_deltaangl_z, None)
+
+    def get_deltavelocity_x(self):
+        """Value returned in meters per second."""
+        return self.__get_scaled_sensor("deltavelocity_x")
+
+    deltavelocity_x_conv = property(get_deltavelocity_x, None)
+
+    def get_deltavelocity_y(self):
+        """Value returned in meters per second."""
+        return self.__get_scaled_sensor("deltavelocity_y")
+
+    deltavelocity_y_conv = property(get_deltavelocity_y, None)
+
+    def get_deltavelocity_z(self):
+        """Value returned in meters per second."""
+        return self.__get_scaled_sensor("deltavelocity_z")
+
+    deltavelocity_z_conv = property(get_deltavelocity_z, None)
+
+    @property
+    def sample_rate(self):
+        """sample_rate: Sample rate in samples per second"""
+        return self._get_iio_dev_attr("sampling_frequency")
+
+    @sample_rate.setter
+    def sample_rate(self, value):
+        self._set_iio_dev_attr_str("sampling_frequency", value)
+
+    @property
+    def current_timestamp_clock(self):
+        """current_timestamp_clock: Source clock for timestamps"""
+        return self._get_iio_dev_attr("current_timestamp_clock")
+
+    @current_timestamp_clock.setter
+    def current_timestamp_clock(self, value):
+        self._set_iio_dev_attr_str("current_timestamp_clock", value)
+
+    @property
+    def anglvel_x_calibbias(self):
+        """User calibration offset for gyroscope for the x-axis."""
+        return self._get_iio_attr("anglvel_x", "calibbias", False)
+
+    @anglvel_x_calibbias.setter
+    def anglvel_x_calibbias(self, value):
+        self._set_iio_attr("anglvel_x", "calibbias", False, value)
+
+    @property
+    def anglvel_y_calibbias(self):
+        """User calibration offset for gyroscope for the y-axis."""
+        return self._get_iio_attr("anglvel_y", "calibbias", False)
+
+    @anglvel_y_calibbias.setter
+    def anglvel_y_calibbias(self, value):
+        self._set_iio_attr("anglvel_y", "calibbias", False, value)
+
+    @property
+    def anglvel_z_calibbias(self):
+        """User calibration offset for gyroscope for the z-axis."""
+        return self._get_iio_attr("anglvel_z", "calibbias", False)
+
+    @anglvel_z_calibbias.setter
+    def anglvel_z_calibbias(self, value):
+        self._set_iio_attr("anglvel_z", "calibbias", False, value)
+
+    @property
+    def accel_x_calibbias(self):
+        """User calibration offset for accelerometer for the x-axis."""
+        return self._get_iio_attr("accel_x", "calibbias", False)
+
+    @accel_x_calibbias.setter
+    def accel_x_calibbias(self, value):
+        self._set_iio_attr("accel_x", "calibbias", False, value)
+
+    @property
+    def accel_y_calibbias(self):
+        """User calibration offset for accelerometer for the y-axis."""
+        return self._get_iio_attr("accel_y", "calibbias", False)
+
+    @accel_y_calibbias.setter
+    def accel_y_calibbias(self, value):
+        self._set_iio_attr("accel_y", "calibbias", False, value)
+
+    @property
+    def accel_z_calibbias(self):
+        """User calibration offset for accelerometer for the z-axis."""
+        return self._get_iio_attr("accel_z", "calibbias", False)
+
+    @accel_z_calibbias.setter
+    def accel_z_calibbias(self, value):
+        self._set_iio_attr("accel_z", "calibbias", False, value)
+
+    @property
+    def anglvel_x_calibscale(self):
+        """Calibscale value for gyroscope for the x-axis."""
+        return self._get_iio_attr("anglvel_x", "calibscale", False)
+
+    @anglvel_x_calibscale.setter
+    def anglvel_x_calibscale(self, value):
+        self._set_iio_attr("anglvel_x", "calibscale", False, value)
+
+    @property
+    def anglvel_y_calibscale(self):
+        """Calibscale value for gyroscope for the y-axis."""
+        return self._get_iio_attr("anglvel_y", "calibscale", False)
+
+    @anglvel_y_calibscale.setter
+    def anglvel_y_calibscale(self, value):
+        self._set_iio_attr("anglvel_y", "calibscale", False, value)
+
+    @property
+    def anglvel_z_calibscale(self):
+        """Calibscale value for gyroscope for the z-axis."""
+        return self._get_iio_attr("anglvel_z", "calibscale", False)
+
+    @anglvel_z_calibscale.setter
+    def anglvel_z_calibscale(self, value):
+        self._set_iio_attr("anglvel_z", "calibscale", False, value)
+
+    @property
+    def accel_x_calibscale(self):
+        """Calibscale value for accelerometer for the x-axis."""
+        return self._get_iio_attr("accel_x", "calibscale", False)
+
+    @accel_x_calibscale.setter
+    def accel_x_calibscale(self, value):
+        self._set_iio_attr("accel_x", "calibscale", False, value)
+
+    @property
+    def accel_y_calibscale(self):
+        """Calibcale value for accelerometer for the y-axis."""
+        return self._get_iio_attr("accel_y", "calibscale", False)
+
+    @accel_y_calibscale.setter
+    def accel_y_calibscale(self, value):
+        self._set_iio_attr("accel_y", "calibscale", False, value)
+
+    @property
+    def accel_z_calibscale(self):
+        """Calibscale for accelerometer for the z-axis."""
+        return self._get_iio_attr("accel_z", "calibscale", False)
+
+    @accel_z_calibscale.setter
+    def accel_z_calibscale(self, value):
+        self._set_iio_attr("accel_z", "calibscale", False, value)
+
+    @property
+    def anglvel_x_filter_low_pass_3db_frequency(self):
+        """Bandwidth for gyroscope for the x-axis."""
+        return self._get_iio_attr("anglvel_x", "filter_low_pass_3db_frequency", False)
+
+    @anglvel_x_filter_low_pass_3db_frequency.setter
+    def anglvel_x_filter_low_pass_3db_frequency(self, value):
+        self._set_iio_attr("anglvel_x", "filter_low_pass_3db_frequency", False, value)
+
+    @property
+    def anglvel_y_filter_low_pass_3db_frequency(self):
+        """Bandwidth for gyroscope for the y-axis."""
+        return self._get_iio_attr("anglvel_y", "filter_low_pass_3db_frequency", False)
+
+    @anglvel_y_filter_low_pass_3db_frequency.setter
+    def anglvel_y_filter_low_pass_3db_frequency(self, value):
+        self._set_iio_attr("anglvel_y", "filter_low_pass_3db_frequency", False, value)
+
+    @property
+    def anglvel_z_filter_low_pass_3db_frequency(self):
+        """Bandwidth for gyroscope for the z-axis."""
+        return self._get_iio_attr("anglvel_z", "filter_low_pass_3db_frequency", False)
+
+    @anglvel_z_filter_low_pass_3db_frequency.setter
+    def anglvel_z_filter_low_pass_3db_frequency(self, value):
+        self._set_iio_attr("anglvel_z", "filter_low_pass_3db_frequency", False, value)
+
+    @property
+    def accel_x_filter_low_pass_3db_frequency(self):
+        """Bandwidth for accelerometer for the x-axis."""
+        return self._get_iio_attr("accel_x", "filter_low_pass_3db_frequency", False)
+
+    @accel_x_filter_low_pass_3db_frequency.setter
+    def accel_x_filter_low_pass_3db_frequency(self, value):
+        self._set_iio_attr("accel_x", "filter_low_pass_3db_frequency", False, value)
+
+    @property
+    def accel_y_filter_low_pass_3db_frequency(self):
+        """Bandwidth for accelerometer for the y-axis."""
+        return self._get_iio_attr("accel_y", "filter_low_pass_3db_frequency", False)
+
+    @accel_y_filter_low_pass_3db_frequency.setter
+    def accel_y_filter_low_pass_3db_frequency(self, value):
+        self._set_iio_attr("accel_y", "filter_low_pass_3db_frequency", False, value)
+
+    @property
+    def accel_z_filter_low_pass_3db_frequency(self):
+        """Bandwidth for accelerometer for the z-axis."""
+        return self._get_iio_attr("accel_z", "filter_low_pass_3db_frequency", False)
+
+    @accel_z_filter_low_pass_3db_frequency.setter
+    def accel_z_filter_low_pass_3db_frequency(self, value):
+        self._set_iio_attr("accel_z", "filter_low_pass_3db_frequency", False, value)
+
+    @property
+    def firmware_revision(self):
+        """firmware_revision: the firmware revision for the internal firmware"""
+        return self._get_iio_debug_attr_str("firmware_revision")
+
+    @property
+    def firmware_date(self):
+        """firmware_date: the factory configuration date"""
+        return self._get_iio_debug_attr_str("firmware_date")
+
+    @property
+    def product_id(self):
+        """product_id: the numerical portion of the device number"""
+        return self._get_iio_debug_attr("product_id")
+
+    @property
+    def serial_number(self):
+        """serial_number: lot specific serial number"""
+        return self._get_iio_debug_attr_str("serial_number")
+
+    @property
+    def flash_count(self):
+        """flash_counter: flash memory write count"""
+        return self._get_iio_debug_attr("flash_count")
+
+    class _temp_channel(attribute):
+        """ADIS16550 temperature channel."""
+
+        def __init__(self, ctrl, channel_name):
+            self.name = channel_name
+            self._ctrl = ctrl
+
+        @property
+        def raw(self):
+            """ADIS16550 raw value"""
+            return self._get_iio_attr(self.name, "raw", False)
+
+        @property
+        def scale(self):
+            """ADIS16550 scale value"""
+            return self._get_iio_attr(self.name, "scale", False)
+
+        @property
+        def offset(self):
+            """ADIS16550 offset value"""
+            return self._get_iio_attr(self.name, "offset", False)
+
+    class _simple_channel(attribute):
+        """ADIS16550 basic channel, only scale an raw values"""
+
+        def __init__(self, ctrl, channel_name):
+            self.name = channel_name
+            self._ctrl = ctrl
+
+        @property
+        def raw(self):
+            """ADIS16550 raw value"""
+            return self._get_iio_attr(self.name, "raw", False)
+
+        @property
+        def scale(self):
+            """ADIS16550 scale value"""
+            return self._get_iio_attr(self.name, "scale", False)
+
+    class _extended_channel(_simple_channel):
+        """ADIS16550 pressure channel."""
+
+        def __init__(self, ctrl, channel_name):
+            self.name = channel_name
+            self._ctrl = ctrl
+
+        @property
+        def calibbias(self):
+            """ADIS16550 calibration offset"""
+            return self._get_iio_attr(self.name, "calibbias", False)
+
+        @calibbias.setter
+        def calibbias(self, value):
+            self._set_iio_attr(self.name, "calibbias", False, value)
+
+        @property
+        def calibscale(self):
+            """ADIS16550 calibration scale"""
+            return self._get_iio_attr(self.name, "calibscale", False)
+
+        @calibscale.setter
+        def calibscale(self, value):
+            self._set_iio_attr(self.name, "calibscale", False, value)
+
+        @property
+        def filter_low_pass_3db_frequency(self):
+            """ADIS16550 channel bandwidth"""
+            return self._get_iio_attr(self.name, "filter_low_pass_3db_frequency", False)
+
+        @filter_low_pass_3db_frequency.setter
+        def filter_low_pass_3db_frequency(self, value):
+            self._set_iio_attr(self.name, "filter_low_pass_3db_frequency", False, value)
+
+    class _anglvel_accel_channels(_extended_channel):
+        """ADIS16550 gyro and accelerometer channels."""
+
+        def __init__(self, ctrl, channel_name):
+            self.name = channel_name
+            self._ctrl = ctrl
+
+    class _delta_channels(_simple_channel):
+        """ADIS16550 delta angle and delta velocity channels."""
+
+        def __init__(self, ctrl, channel_name):
+            self.name = channel_name
+            self._ctrl = ctrl
diff --git a/doc/source/devices/adi.adis16550.rst b/doc/source/devices/adi.adis16550.rst
new file mode 100644
index 000000000..f16fb307c
--- /dev/null
+++ b/doc/source/devices/adi.adis16550.rst
@@ -0,0 +1,8 @@
+adis16550
+====================
+
+.. autoclass:: adi.adis16550
+   :members:
+   :undoc-members:
+   :show-inheritance:
+   :inherited-members:
diff --git a/doc/source/devices/index.rst b/doc/source/devices/index.rst
index 52df1b849..b22265878 100644
--- a/doc/source/devices/index.rst
+++ b/doc/source/devices/index.rst
@@ -79,6 +79,7 @@ Supported Devices
    adi.adis16507
    adi.adis16545
    adi.adis16547
+   adi.adis16550
    adi.adl5240
    adi.adl5960
    adi.admv8818
diff --git a/examples/adis16550_example.py b/examples/adis16550_example.py
new file mode 100644
index 000000000..95b8f8ad4
--- /dev/null
+++ b/examples/adis16550_example.py
@@ -0,0 +1,59 @@
+# Copyright (C) 2024 Analog Devices, Inc.
+#
+# SPDX short identifier: ADIBSD
+import sys
+
+import adi
+import matplotlib.pyplot as plt
+
+# Set up ADIS16550
+my_dev_name = sys.argv[1]
+my_uri = sys.argv[2]
+
+dev = adi.adis16550(device_name=my_dev_name, uri=my_uri)
+
+dev.rx_output_type = "raw"
+dev.rx_enabled_channels = [0, 1, 2, 3, 4, 5]
+# dev.rx_enabled_delta_channels = [7, 8, 9, 10, 11, 12]
+dev.sample_rate = 10
+dev.rx_buffer_size = 10
+
+print("\nX acceleration: " + str(dev.accel_x_conv) + " m/s^2")
+print("Y acceleration: " + str(dev.accel_y_conv) + " m/s^2")
+print("Z acceleration: " + str(dev.accel_z_conv) + " m/s^2")
+
+print("\nX angular velocity: " + str(dev.anglvel_x_conv) + " rad/s")
+print("Y angular velocity: " + str(dev.anglvel_y_conv) + " rad/s")
+print("Z angular velocity: " + str(dev.anglvel_z_conv) + " rad/s")
+
+print("\nX delta velocity: " + str(dev.deltavelocity_x_conv) + " m/s")
+print("Y delta velocity: " + str(dev.deltavelocity_y_conv) + " m/s")
+print("Z delta velocity: " + str(dev.deltavelocity_z_conv) + " m/s")
+
+print("\nX delta angle: " + str(dev.deltaangl_x_conv) + " rad")
+print("Y delta angle: " + str(dev.deltaangl_y_conv) + " rad")
+print("Z delta angle: " + str(dev.deltaangl_z_conv) + " rad")
+
+dev.sample_rate = 2000
+dev.magn_x_filter_low_pass_3db_frequency = 100
+dev.anglvel_y_calibscale = 30
+dev.anglvel_x_calibbias = 100
+
+print("\nSampling frequency: " + str(dev.sample_rate))
+
+print("Temperature raw value: " + str(dev.temp.raw))
+print("Temperature scale value: " + str(dev.temp.scale))
+print("Temperature offset value: " + str(dev.temp.offset))
+
+print("X-axis gyro channel calibbias value: " + str(dev.anglvel_x_calibbias))
+print("X-axis gyro channel calibscale value: " + str(dev.anglvel_y_calibscale))
+print("X-axis magnetometer bandwidth: " + str(dev.magn_x_filter_low_pass_3db_frequency))
+
+for _ in range(100):
+    data = dev.rx()
+    plt.clf()
+    for i, d in enumerate(data):
+        plt.plot(d, label=dev._rx_channel_names[dev.rx_enabled_channels[i]])
+    plt.legend()
+    plt.show(block=False)
+    plt.pause(0.1)
diff --git a/supported_parts.md b/supported_parts.md
index b99b05617..035de9857 100644
--- a/supported_parts.md
+++ b/supported_parts.md
@@ -143,6 +143,8 @@
 - ADIS16507
 - ADIS16545
 - ADIS16547
+- ADIS16550
+- ADIS16550W
 - ADL5240
 - ADL5960
 - ADMV8818
diff --git a/test/emu/devices/adis16550.xml b/test/emu/devices/adis16550.xml
new file mode 100644
index 000000000..45c2a414b
--- /dev/null
+++ b/test/emu/devices/adis16550.xml
@@ -0,0 +1,149 @@
+<?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>
+  <!ATTLIST context description CDATA #IMPLIED>
+  <!ATTLIST context-attribute name CDATA #REQUIRED>
+  <!ATTLIST context-attribute value CDATA #REQUIRED>
+  <!ATTLIST device id CDATA #REQUIRED>
+  <!ATTLIST device name CDATA #IMPLIED>
+  <!ATTLIST channel id CDATA #REQUIRED>
+  <!ATTLIST channel type (input|output) #REQUIRED>
+  <!ATTLIST channel name CDATA #IMPLIED>
+  <!ATTLIST scan-element index CDATA #REQUIRED>
+  <!ATTLIST scan-element format CDATA #REQUIRED>
+  <!ATTLIST scan-element scale CDATA #IMPLIED>
+  <!ATTLIST attribute name CDATA #REQUIRED>
+  <!ATTLIST attribute filename CDATA #IMPLIED>
+  <!ATTLIST attribute value CDATA #IMPLIED>
+  <!ATTLIST debug-attribute name CDATA #REQUIRED>
+  <!ATTLIST debug-attribute value CDATA #IMPLIED>
+  <!ATTLIST buffer-attribute name CDATA #REQUIRED>
+  <!ATTLIST buffer-attribute value CDATA #IMPLIED>
+]>
+<context name="network" description="10.42.0.83 Linux analog 6.1.54-v7l+ #8 SMP Mon Sep 30 11:56:09 BST 2024 armv7l">
+   <context-attribute name="hw_carrier" value="Raspberry Pi 4 Model B Rev 1.2" />
+   <context-attribute name="dtoverlay" value="vc4-kms-v3d,adis16550" />
+   <context-attribute name="local,kernel" value="6.1.54-v7l+" />
+   <context-attribute name="uri" value="ip:10.42.0.83" />
+   <context-attribute name="ip,ip-addr" value="10.42.0.83" />
+   <device id="hwmon0" name="cpu_thermal">
+      <channel id="temp1" type="input">
+         <attribute name="crit" filename="temp1_crit" value="110000" />
+         <attribute name="input" filename="temp1_input" value="65731" />
+      </channel>
+   </device>
+   <device id="hwmon1" name="rpi_volt">
+      <channel id="in0" type="input">
+         <attribute name="lcrit_alarm" filename="in0_lcrit_alarm" value="0" />
+      </channel>
+   </device>
+   <device id="iio:device0" name="adis16550">
+      <channel id="anglvel_x" type="input">
+         <scan-element index="0" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="calibbias" filename="in_anglvel_x_calibbias" value="100" />
+         <attribute name="calibscale" filename="in_anglvel_x_calibscale" value="0" />
+         <attribute name="filter_low_pass_3db_frequency" filename="in_anglvel_filter_low_pass_3db_frequency" value="0" />
+         <attribute name="raw" filename="in_anglvel_x_raw" value="294318" />
+         <attribute name="scale" filename="in_anglvel_scale" value="0.000000003" />
+      </channel>
+      <channel id="anglvel_y" type="input">
+         <scan-element index="1" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="calibbias" filename="in_anglvel_y_calibbias" value="0" />
+         <attribute name="calibscale" filename="in_anglvel_y_calibscale" value="30" />
+         <attribute name="filter_low_pass_3db_frequency" filename="in_anglvel_filter_low_pass_3db_frequency" value="0" />
+         <attribute name="raw" filename="in_anglvel_y_raw" value="-656865" />
+         <attribute name="scale" filename="in_anglvel_scale" value="0.000000003" />
+      </channel>
+      <channel id="anglvel_z" type="input">
+         <scan-element index="2" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="calibbias" filename="in_anglvel_z_calibbias" value="0" />
+         <attribute name="calibscale" filename="in_anglvel_z_calibscale" value="0" />
+         <attribute name="filter_low_pass_3db_frequency" filename="in_anglvel_filter_low_pass_3db_frequency" value="0" />
+         <attribute name="raw" filename="in_anglvel_z_raw" value="431669" />
+         <attribute name="scale" filename="in_anglvel_scale" value="0.000000003" />
+      </channel>
+      <channel id="accel_x" type="input">
+         <scan-element index="3" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="calibbias" filename="in_accel_x_calibbias" value="0" />
+         <attribute name="calibscale" filename="in_accel_x_calibscale" value="0" />
+         <attribute name="filter_low_pass_3db_frequency" filename="in_accel_filter_low_pass_3db_frequency" value="0" />
+         <attribute name="raw" filename="in_accel_x_raw" value="-210881" />
+         <attribute name="scale" filename="in_accel_scale" value="0.000000095" />
+      </channel>
+      <channel id="accel_y" type="input">
+         <scan-element index="4" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="calibbias" filename="in_accel_y_calibbias" value="0" />
+         <attribute name="calibscale" filename="in_accel_y_calibscale" value="0" />
+         <attribute name="filter_low_pass_3db_frequency" filename="in_accel_filter_low_pass_3db_frequency" value="0" />
+         <attribute name="raw" filename="in_accel_y_raw" value="1598455" />
+         <attribute name="scale" filename="in_accel_scale" value="0.000000095" />
+      </channel>
+      <channel id="accel_z" type="input">
+         <scan-element index="5" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="calibbias" filename="in_accel_z_calibbias" value="0" />
+         <attribute name="calibscale" filename="in_accel_z_calibscale" value="0" />
+         <attribute name="filter_low_pass_3db_frequency" filename="in_accel_filter_low_pass_3db_frequency" value="0" />
+         <attribute name="raw" filename="in_accel_z_raw" value="103145573" />
+         <attribute name="scale" filename="in_accel_scale" value="0.000000095" />
+      </channel>
+      <channel id="temp0" type="input">
+         <scan-element index="6" format="be:s16/32&gt;&gt;0" scale="4.000000" />
+         <attribute name="offset" filename="in_temp0_offset" value="6250" />
+         <attribute name="raw" filename="in_temp0_raw" value="4369" />
+         <attribute name="scale" filename="in_temp0_scale" value="4" />
+      </channel>
+      <channel id="deltaangl_x" type="input">
+         <scan-element index="7" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="raw" filename="in_deltaangl_x_raw" value="-86" />
+         <attribute name="scale" filename="in_deltaangl_scale" value="0.000000006" />
+      </channel>
+      <channel id="deltaangl_y" type="input">
+         <scan-element index="8" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="raw" filename="in_deltaangl_y_raw" value="-162" />
+         <attribute name="scale" filename="in_deltaangl_scale" value="0.000000006" />
+      </channel>
+      <channel id="deltaangl_z" type="input">
+         <scan-element index="9" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="raw" filename="in_deltaangl_z_raw" value="169" />
+         <attribute name="scale" filename="in_deltaangl_scale" value="0.000000006" />
+      </channel>
+      <channel id="deltavelocity_x" type="input">
+         <scan-element index="10" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="raw" filename="in_deltavelocity_x_raw" value="246" />
+         <attribute name="scale" filename="in_deltavelocity_scale" value="0.000000058" />
+      </channel>
+      <channel id="deltavelocity_y" type="input">
+         <scan-element index="11" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="raw" filename="in_deltavelocity_y_raw" value="-75" />
+         <attribute name="scale" filename="in_deltavelocity_scale" value="0.000000058" />
+      </channel>
+      <channel id="deltavelocity_z" type="input">
+         <scan-element index="12" format="be:S32/32&gt;&gt;0" scale="0.000000" />
+         <attribute name="raw" filename="in_deltavelocity_z_raw" value="84684" />
+         <attribute name="scale" filename="in_deltavelocity_scale" value="0.000000058" />
+      </channel>
+      <channel id="timestamp" type="input">
+         <scan-element index="13" format="le:S64/64&gt;&gt;0" />
+      </channel>
+      <attribute name="current_timestamp_clock" value="realtime " />
+      <attribute name="sampling_frequency" value="2000.000000" />
+      <attribute name="waiting_for_supplier" value="0" />
+      <buffer-attribute name="data_available" value="64" />
+      <buffer-attribute name="direction" value="in" />
+      <debug-attribute name="flash_count" value="13" />
+      <debug-attribute name="firmware_date" value="28-04-2021" />
+      <debug-attribute name="firmware_revision" value="1.5" />
+      <debug-attribute name="product_id" value="16550" />
+      <debug-attribute name="serial_number" value="0x000000b6" />
+      <debug-attribute name="direct_reg_access" value="0x0" />
+   </device>
+   <device id="trigger0" name="adis16550-dev0" />
+</context>
\ No newline at end of file
diff --git a/test/emu/hardware_map.yml b/test/emu/hardware_map.yml
index 6477c641c..48b1938f9 100644
--- a/test/emu/hardware_map.yml
+++ b/test/emu/hardware_map.yml
@@ -584,6 +584,15 @@ adis16480:
   - pyadi_iio_class_support:
       - adis16480
 
+adis16550:
+  - adis16550
+  - emulate:
+      - filename: adis16550.xml
+      - data_devices:
+        - iio:device0
+  - pyadi_iio_class_support:
+      - adis16550
+
 ad7124-8:
   - ad7124
   - pyadi_iio_class_support:
diff --git a/test/test_adis16550.py b/test/test_adis16550.py
new file mode 100644
index 000000000..43b19888a
--- /dev/null
+++ b/test/test_adis16550.py
@@ -0,0 +1,80 @@
+import iio
+
+import adi
+import pytest
+
+hardware = "adis16550"
+classname = "adi.adis16550"
+device_name = "adis16550"
+
+
+def do_mock():
+    def mock_set_trigger(self, value):
+        pass
+
+    # Mock the _set_trigger method in iio.Device
+    iio.Device._set_trigger = mock_set_trigger
+
+
+#########################################
+@pytest.mark.iio_hardware(hardware, False)
+def test_adis16550_conv_data(iio_uri):
+    do_mock()
+    adis16550 = adi.adis16550(uri=iio_uri)
+
+    assert adis16550.accel_x_conv != 0.0
+    assert adis16550.accel_y_conv != 0.0
+    assert adis16550.accel_z_conv != 0.0
+    assert adis16550.anglvel_x_conv != 0.0
+    assert adis16550.anglvel_y_conv != 0.0
+    assert adis16550.anglvel_z_conv != 0.0
+    assert adis16550.temp_conv != 0.0
+
+
+#########################################
+@pytest.mark.iio_hardware(hardware, True)
+@pytest.mark.parametrize("classname", [(classname)])
+@pytest.mark.parametrize(
+    "attr, start, stop, step, tol",
+    [
+        ("anglvel_x_calibbias", -2147483648, 2147483647, 1, 0),
+        ("anglvel_y_calibbias", -2147483648, 2147483647, 1, 0),
+        ("anglvel_z_calibbias", -2147483648, 2147483647, 1, 0),
+        ("accel_x_calibbias", -2147483648, 2147483647, 1, 0),
+        ("accel_y_calibbias", -2147483648, 2147483647, 1, 0),
+        ("accel_z_calibbias", -2147483648, 2147483647, 1, 0),
+        ("anglvel_x_calibscale", 0, 65535, 1, 0),
+        ("anglvel_y_calibscale", 0, 65535, 1, 0),
+        ("anglvel_z_calibscale", 0, 65535, 1, 0),
+        ("accel_x_calibscale", 0, 65535, 1, 0),
+        ("accel_y_calibscale", 0, 65535, 1, 0),
+        ("accel_z_calibscale", 0, 65535, 1, 0),
+    ],
+)
+def test_adis16550_attr(
+    test_attribute_single_value, iio_uri, classname, attr, start, stop, step, tol
+):
+    do_mock()
+    test_attribute_single_value(iio_uri, classname, attr, start, stop, step, tol)
+
+
+#########################################
+@pytest.mark.iio_hardware(hardware, True)
+@pytest.mark.parametrize("classname", [(classname)])
+@pytest.mark.parametrize(
+    "attr, values, tol, repeats",
+    [
+        ("sample_rate", [5, 10, 246, 1230, 2460], 0.5, 2),
+        ("anglvel_x_filter_low_pass_3db_frequency", [0, 55, 275, 310], 0.5, 2),
+        ("anglvel_y_filter_low_pass_3db_frequency", [0, 55, 275, 310], 0.5, 2),
+        ("anglvel_z_filter_low_pass_3db_frequency", [0, 55, 275, 310], 0.5, 2),
+        ("accel_x_filter_low_pass_3db_frequency", [0, 55, 275, 310], 0.5, 2),
+        ("accel_y_filter_low_pass_3db_frequency", [0, 55, 275, 310], 0.5, 2),
+        ("accel_z_filter_low_pass_3db_frequency", [0, 55, 275, 310], 0.5, 2),
+    ],
+)
+def test_adis16550_attr_multiple_val(
+    test_attribute_multiple_values, iio_uri, classname, attr, values, tol, repeats,
+):
+    do_mock()
+    test_attribute_multiple_values(iio_uri, classname, attr, values, tol, repeats)