diff options
Diffstat (limited to 'bindings')
26 files changed, 4533 insertions, 0 deletions
diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt new file mode 100644 index 0000000..e2afcf0 --- /dev/null +++ b/bindings/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(csharp) +add_subdirectory(matlab) +add_subdirectory(python) diff --git a/bindings/csharp/.gitignore b/bindings/csharp/.gitignore new file mode 100644 index 0000000..475b306 --- /dev/null +++ b/bindings/csharp/.gitignore @@ -0,0 +1,3 @@ +AssemblyInfo.cs +libiio-sharp-0.5.pc +libiio-sharp.dll.config diff --git a/bindings/csharp/AssemblyInfo.cs.in b/bindings/csharp/AssemblyInfo.cs.in new file mode 100644 index 0000000..5d1de04 --- /dev/null +++ b/bindings/csharp/AssemblyInfo.cs.in @@ -0,0 +1,5 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly:AssemblyVersion("@LIBIIO_CS_VERSION@")] +[assembly:AssemblyDelaySign(false)] diff --git a/bindings/csharp/Attr.cs b/bindings/csharp/Attr.cs new file mode 100644 index 0000000..2ddcc3e --- /dev/null +++ b/bindings/csharp/Attr.cs @@ -0,0 +1,102 @@ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2015 Analog Devices, Inc. + * Author: Paul Cercueil <paul.cercueil@analog.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * */ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace iio +{ + /// <summary><see cref="iio.Attr"/> class: + /// Contains the representation of a channel or device attribute.</summary> + public abstract class Attr + { + /// <summary>The name of this attribute.</summary> + public readonly string name; + + /// <summary>The filename in sysfs to which this attribute is bound.</summary> + public readonly string filename; + + internal Attr(string name, string filename = null) + { + this.filename = filename == null ? name : filename; + this.name = name; + } + + /// <summary>Read the value of this attribute as a <c>string</c>.</summary> + /// <exception cref="System.Exception">The attribute could not be read.</exception> + public abstract string read(); + + /// <summary>Set this attribute to the value contained in the <c>string</c> argument.</summary> + /// <param name="val">The <c>string</c> value to set the parameter to.</param> + /// <exception cref="System.Exception">The attribute could not be written.</exception> + public abstract void write(string val); + + /// <summary>Read the value of this attribute as a <c>bool</c>.</summary> + /// <exception cref="System.Exception">The attribute could not be read.</exception> + public bool read_bool() + { + string val = read(); + return (val.CompareTo("1") == 0) || (val.CompareTo("Y") == 0); + } + + /// <summary>Read the value of this attribute as a <c>double</c>.</summary> + /// <exception cref="System.Exception">The attribute could not be read.</exception> + public double read_double() + { + return double.Parse(read(), CultureInfo.InvariantCulture); + } + + /// <summary>Read the value of this attribute as a <c>long</c>.</summary> + /// <exception cref="System.Exception">The attribute could not be read.</exception> + public long read_long() + { + return long.Parse(read(), CultureInfo.InvariantCulture); + } + + /// <summary>Set this attribute to the value contained in the <c>bool</c> argument.</summary> + /// <param name="val">The <c>bool</c> value to set the parameter to.</param> + /// <exception cref="System.Exception">The attribute could not be written.</exception> + public void write(bool val) + { + if (val) + write("1"); + else + write("0"); + } + + /// <summary>Set this attribute to the value contained in the <c>long</c> argument.</summary> + /// <param name="val">The <c>long</c> value to set the parameter to.</param> + /// <exception cref="System.Exception">The attribute could not be written.</exception> + public void write(long val) + { + write(val.ToString(CultureInfo.InvariantCulture)); + } + + /// <summary>Set this attribute to the value contained in the <c>double</c> argument.</summary> + /// <param name="val">The <c>double</c> value to set the parameter to.</param> + /// <exception cref="System.Exception">The attribute could not be written.</exception> + public void write(double val) + { + write(val.ToString(CultureInfo.InvariantCulture)); + } + } +} diff --git a/bindings/csharp/CMakeLists.txt b/bindings/csharp/CMakeLists.txt new file mode 100644 index 0000000..7e9d19b --- /dev/null +++ b/bindings/csharp/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 2.8.7) +project(libiio-sharp NONE) + +if (WIN32) + set(MCS_EXECUTABLE_NAME csc) +else() + set(MCS_EXECUTABLE_NAME mcs) +endif() + +find_program(MCS_EXECUTABLE + NAMES ${MCS_EXECUTABLE_NAME} + HINTS "C:/Windows/Microsoft.NET/Framework/v4.0.30319" + PATHS ENV MCS_EXECUTABLE_PATH + DOC "C# compiler") +mark_as_advanced(MCS_EXECUTABLE) + +if (MCS_EXECUTABLE) + option(CSHARP_BINDINGS "Install C# bindings" ON) + + if (CSHARP_BINDINGS) + set(LIBIIO_CS_PC_IN "${CMAKE_CURRENT_SOURCE_DIR}/libiio-sharp.pc.cmakein") + set(LIBIIO_CS_PC "${CMAKE_CURRENT_BINARY_DIR}/libiio-sharp-${VERSION}.pc") + configure_file(${LIBIIO_CS_PC_IN} ${LIBIIO_CS_PC} @ONLY) + if(NOT SKIP_INSTALL_ALL) + install(FILES ${LIBIIO_CS_PC} DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig") + endif() + + set(LIBIIO_CS_DLL_CONFIG_IN "${CMAKE_CURRENT_SOURCE_DIR}/libiio-sharp.dll.config.cmakein") + set(LIBIIO_CS_DLL_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/libiio-sharp.dll.config") + configure_file(${LIBIIO_CS_DLL_CONFIG_IN} ${LIBIIO_CS_DLL_CONFIG} @ONLY) + if(NOT SKIP_INSTALL_ALL) + install(FILES ${LIBIIO_CS_DLL_CONFIG} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cli/libiio-sharp-${VERSION}) + endif() + + set(LIBIIO_CS_VERSION ${VERSION}.0.0) + set(LIBIIO_CS_INFO_IN ${CMAKE_CURRENT_SOURCE_DIR}/AssemblyInfo.cs.in) + set(LIBIIO_CS_INFO ${CMAKE_CURRENT_BINARY_DIR}/AssemblyInfo.cs) + configure_file(${LIBIIO_CS_INFO_IN} ${LIBIIO_CS_INFO} @ONLY) + + set(LIBIIO_CS_DLL "${CMAKE_CURRENT_BINARY_DIR}/libiio-sharp.dll") + set(LIBIIO_CS_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/Attr.cs + ${CMAKE_CURRENT_SOURCE_DIR}/Channel.cs + ${CMAKE_CURRENT_SOURCE_DIR}/Context.cs + ${CMAKE_CURRENT_SOURCE_DIR}/Device.cs + ${CMAKE_CURRENT_SOURCE_DIR}/IOBuffer.cs + ${CMAKE_CURRENT_SOURCE_DIR}/Trigger.cs + ${LIBIIO_CS_INFO} + ) + + foreach(SRC ${LIBIIO_CS_SOURCES}) + file(TO_NATIVE_PATH ${SRC} TMP) + set(LIBIIO_CS_SOURCES_REALPATH ${LIBIIO_CS_SOURCES_REALPATH} ${TMP}) + endforeach(SRC) + + file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/key.snk SIGN_KEY) + file(TO_NATIVE_PATH ${LIBIIO_CS_DLL} LIBIIO_CS_DLL_OUT) + + add_custom_command(OUTPUT ${LIBIIO_CS_DLL} + COMMAND ${MCS_EXECUTABLE} /target:library /out:${LIBIIO_CS_DLL_OUT} /debug /keyfile:${SIGN_KEY} ${LIBIIO_CS_SOURCES_REALPATH} + DEPENDS ${LIBIIO_CS_SOURCES} + ) + + add_custom_target(libiio-sharp ALL DEPENDS ${LIBIIO_CS_DLL}) + + if(NOT SKIP_INSTALL_ALL) + install(FILES ${LIBIIO_CS_DLL} ${LIBIIO_CS_DLL}.mdb DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/cli/libiio-sharp-${VERSION}) + endif() + endif() +endif() diff --git a/bindings/csharp/Channel.cs b/bindings/csharp/Channel.cs new file mode 100644 index 0000000..491a4ad --- /dev/null +++ b/bindings/csharp/Channel.cs @@ -0,0 +1,236 @@ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2015 Analog Devices, Inc. + * Author: Paul Cercueil <paul.cercueil@analog.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace iio +{ + /// <summary><see cref="iio.Channel"/> class: + /// Contains the representation of an input or output channel.</summary> + public class Channel + { + private class ChannelAttr : Attr + { + private IntPtr chn; + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_channel_attr_read(IntPtr chn, [In()] string name, [Out()] StringBuilder val, uint len); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_channel_attr_write(IntPtr chn, [In()] string name, string val); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_channel_attr_get_filename(IntPtr chn, [In()] string attr); + + public ChannelAttr(IntPtr chn, string name) : base(name, Marshal.PtrToStringAnsi(iio_channel_attr_get_filename(chn, name))) + { + this.chn = chn; + } + + public override string read() + { + StringBuilder builder = new StringBuilder(1024); + int err = iio_channel_attr_read(chn, name, builder, (uint) builder.Capacity); + if (err < 0) + throw new Exception("Unable to read channel attribute " + err); + return builder.ToString(); + } + + public override void write(string str) + { + int err = iio_channel_attr_write(chn, name, str); + if (err < 0) + throw new Exception("Unable to write channel attribute " + err); + } + } + + + private IntPtr chn; + private uint sample_size; + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_channel_get_id(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_channel_get_name(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_channel_get_attrs_count(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_channel_get_attr(IntPtr chn, uint index); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool iio_channel_is_output(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool iio_channel_is_scan_element(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void iio_channel_enable(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void iio_channel_disable(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool iio_channel_is_enabled(IntPtr chn); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_channel_read_raw(IntPtr chn, IntPtr buf, IntPtr dst, uint len); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_channel_write_raw(IntPtr chn, IntPtr buf, IntPtr src, uint len); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_channel_read(IntPtr chn, IntPtr buf, IntPtr dst, uint len); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_channel_write(IntPtr chn, IntPtr buf, IntPtr src, uint len); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_channel_get_data_format(IntPtr chn); + + /// <summary>The name of this channel.</summary> + public readonly string name; + + /// <summary>An identifier of this channel.</summary> + /// <remarks>It is possible that two channels have the same ID, + /// if one is an input channel and the other is an output channel.</remarks> + public readonly string id; + + /// <summary>Contains <c>true</c> if the channel is an output channel, + /// <c>false</c> otherwise.</summary> + public readonly bool output; + + /// <summary>Contains <c>true</c> if the channel is a scan element, + /// <c>false</c> otherwise.</summary> + /// <remarks>If a channel is a scan element, then it is possible to enable it + /// and use it for I/O operations.</remarks> + public readonly bool scan_element; + + /// <summary>A <c>list</c> of all the attributes that this channel has.</summary> + public readonly List<Attr> attrs; + + internal Channel(IntPtr chn) + { + this.chn = chn; + attrs = new List<Attr>(); + sample_size = (uint)Marshal.ReadInt32(iio_channel_get_data_format(this.chn)) / 8; + uint nb_attrs = iio_channel_get_attrs_count(chn); + + for (uint i = 0; i < nb_attrs; i++) + attrs.Add(new ChannelAttr(this.chn, Marshal.PtrToStringAnsi(iio_channel_get_attr(chn, i)))); + + IntPtr name_ptr = iio_channel_get_name(this.chn); + if (name_ptr == IntPtr.Zero) + name = ""; + else + name = Marshal.PtrToStringAnsi(name_ptr); + + id = Marshal.PtrToStringAnsi(iio_channel_get_id(this.chn)); + output = iio_channel_is_output(this.chn); + scan_element = iio_channel_is_scan_element(this.chn); + } + + /// <summary>Enable the current channel, so that it can be used for I/O operations.</summary> + public void enable() + { + iio_channel_enable(this.chn); + } + + /// <summary>Disable the current channel.</summary> + public void disable() + { + iio_channel_disable(this.chn); + } + + /// <summary>Returns whether or not the channel has been enabled.</summary> + public bool is_enabled() + { + return iio_channel_is_enabled(this.chn); + } + + /// <summary>Extract the samples corresponding to this channel from the + /// given <see cref="iio.IOBuffer"/> object.</summary> + /// <param name="buffer">A valid instance of the <see cref="iio.IOBuffer"/> class.</param> + /// <param name="raw">If set to <c>true</c>, the samples are not converted from their + /// hardware format to their host format.</param> + /// <returns>A <c>byte</c> array containing the extracted samples.</returns> + /// <exception cref="System.Exception">The samples could not be read.</exception> + public byte[] read(IOBuffer buffer, bool raw = false) + { + if (!is_enabled()) + throw new Exception("Channel must be enabled before the IOBuffer is instantiated"); + if (this.output) + throw new Exception("Unable to read from output channel"); + + byte[] array = new byte[(int) (buffer.samples_count * sample_size)]; + MemoryStream stream = new MemoryStream(array, true); + GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); + IntPtr addr = handle.AddrOfPinnedObject(); + uint count; + + if (raw) + count = iio_channel_read_raw(this.chn, buffer.buf, addr, buffer.samples_count * sample_size); + else + count = iio_channel_read(this.chn, buffer.buf, addr, buffer.samples_count * sample_size); + handle.Free(); + stream.SetLength((long) count); + return stream.ToArray(); + + } + + /// <summary> + /// Write the specified array of samples corresponding to this channel into the + /// given <see cref="iio.IOBuffer"/> object.</summary> + /// <param name="buffer">A valid instance of the <see cref="iio.IOBuffer"/> class.</param> + /// <param name="array">A <c>byte</c> array containing the samples to write.</param> + /// <param name="raw">If set to <c>true</c>, the samples are not converted from their + /// host format to their native format.</param> + /// <returns>The number of bytes written.</returns> + /// <exception cref="System.Exception">The samples could not be written.</exception> + public uint write(IOBuffer buffer, byte[] array, bool raw = false) + { + if (!is_enabled()) + throw new Exception("Channel must be enabled before the IOBuffer is instantiated"); + if (!this.output) + throw new Exception("Unable to write to an input channel"); + + GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); + IntPtr addr = handle.AddrOfPinnedObject(); + uint count; + + if (raw) + count = iio_channel_write_raw(this.chn, buffer.buf, addr, (uint) array.Length); + else + count = iio_channel_write(this.chn, buffer.buf, addr, (uint) array.Length); + handle.Free(); + + return count; + } + } +} diff --git a/bindings/csharp/Context.cs b/bindings/csharp/Context.cs new file mode 100644 index 0000000..e5c478f --- /dev/null +++ b/bindings/csharp/Context.cs @@ -0,0 +1,231 @@ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2015 Analog Devices, Inc. + * Author: Paul Cercueil <paul.cercueil@analog.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace iio +{ + public class Version + { + public readonly uint major; + public readonly uint minor; + public readonly string git_tag; + + internal Version(uint major, uint minor, string git_tag) + { + this.major = major; + this.minor = minor; + this.git_tag = git_tag; + } + } + + /// <summary><see cref="iio.Context"/> class: + /// Contains the representation of an IIO context.</summary> + public class Context : IDisposable + { + private IntPtr ctx; + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_create_network_context( + [In()][MarshalAs(UnmanagedType.LPStr)] string hostname + ); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_create_context_from_uri( + [In()][MarshalAs(UnmanagedType.LPStr)] string uri + ); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_create_default_context(); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void iio_context_destroy(IntPtr ctx); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_context_get_name(IntPtr ctx); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_context_get_description(IntPtr ctx); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_context_get_xml(IntPtr ctx); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void iio_library_get_version(ref uint major, ref uint minor, [Out()] StringBuilder git_tag); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_context_get_version(IntPtr ctx, ref uint major, ref uint minor, [Out()] StringBuilder git_tag); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_context_get_devices_count(IntPtr ctx); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_context_get_device(IntPtr ctx, uint index); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool iio_device_is_trigger(IntPtr dev); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_context_set_timeout(IntPtr ctx, uint timeout_ms); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_context_clone(IntPtr ctx); + + /// <summary>A XML representation of the current context.</summary> + public readonly string xml; + + /// <summary>The name of the current context.</summary> + public readonly string name; + + /// <summary>Retrieve a human-readable information string about the current context.</summary> + public readonly string description; + public readonly Version library_version, backend_version; + + /// <summary>A <c>List</c> of all the IIO devices present on the current context.</summary> + public readonly List<Device> devices; + + /// <summary>Initializes a new instance of the <see cref="iio.Context"/> class, + /// using the provided URI. For compatibility with existing code, providing + /// an IP address or a hostname here will automatically create a network + /// context.</summary> + /// <param name="uri">URI to use for the IIO context creation</param> + /// <returns>an instance of the <see cref="iio.Context"/> class</returns> + /// <exception cref="System.Exception">The IIO context could not be created.</exception> + public Context(string uri) : this(getContextFromString(uri)) {} + + /// <summary>Initializes a new instance of the <see cref="iio.Context"/> class, + /// using the local or the network backend of the IIO library.</summary> + /// <remarks>This function will create a network context if the IIOD_REMOTE + /// environment variable is set to the hostname where the IIOD server runs. + /// If set to an empty string, the server will be discovered using ZeroConf. + /// If the environment variable is not set, a local context will be created + /// instead.</remarks> + /// <exception cref="System.Exception">The IIO context could not be created.</exception> + public Context() : this(iio_create_default_context()) {} + + private static IntPtr getContextFromString(string str) + { + IntPtr ptr = iio_create_context_from_uri(str); + if (ptr == IntPtr.Zero) + ptr = iio_create_network_context(str); + return ptr; + } + + private Context(IntPtr ctx) + { + this.ctx = ctx; + + if (ctx == IntPtr.Zero) + throw new Exception("Unable to create IIO context"); + + uint nb_devices = iio_context_get_devices_count(ctx); + + devices = new List<Device>(); + for (uint i = 0; i < nb_devices; i++) + { + IntPtr ptr = iio_context_get_device(ctx, i); + if (iio_device_is_trigger(ptr)) + devices.Add(new Trigger(this, ptr)); + else + devices.Add(new Device(this, ptr)); + } + + xml = Marshal.PtrToStringAnsi(iio_context_get_xml(ctx)); + name = Marshal.PtrToStringAnsi(iio_context_get_name(ctx)); + description = Marshal.PtrToStringAnsi(iio_context_get_description(ctx)); + + uint major = 0; + uint minor = 0; + StringBuilder builder = new StringBuilder(8); + iio_library_get_version(ref major, ref minor, builder); + library_version = new Version(major, minor, builder.ToString()); + + major = 0; + minor = 0; + builder.Clear(); + int err = iio_context_get_version(ctx, ref major, ref minor, builder); + if (err < 0) + throw new Exception("Unable to read backend version"); + backend_version = new Version(major, minor, builder.ToString()); + } + + ~Context() + { + if (ctx != IntPtr.Zero) + Dispose(false); + } + + /// <summary>Clone this instance.</summary> + public Context clone() + { + return new Context(iio_context_clone(this.ctx)); + } + + /// <summary>Get the <see cref="iio.Device"/> object of the specified name.</summary> + /// <param name="name">Name or ID of the device to look for</param> + /// <exception cref="System.Exception">The IIO device with the specified + /// name or ID could not be found in the current context.</exception> + public Device get_device(string name) + { + foreach (Device each in devices) { + if (each.name.CompareTo(name) == 0 || + each.id.CompareTo(name) == 0) + return each; + } + + throw new Exception("Device " + name + " not found"); + } + + /// <summary>Set a timeout for I/O operations.</summary> + /// <param name="timeout">The timeout value, in milliseconds</param> + /// <exception cref="System.Exception">The timeout could not be applied.</exception> + public void set_timeout(uint timeout) + { + int ret = iio_context_set_timeout(ctx, timeout); + if (ret < 0) + throw new Exception("Unable to set timeout"); + } + + /// <summary>Releases all resource used by the <see cref="iio.Context"/> object.</summary> + /// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="iio.Context"/>. The + /// <see cref="Dispose"/> method leaves the <see cref="iio.Context"/> in an unusable state. After calling + /// <see cref="Dispose"/>, you must release all references to the <see cref="iio.Context"/> so the garbage + /// collector can reclaim the memory that the <see cref="iio.Context"/> was occupying.</remarks> + public void Dispose() + { + Dispose(true); + } + + private void Dispose(bool clean) + { + if (ctx != IntPtr.Zero) + { + if (clean) + GC.SuppressFinalize(this); + iio_context_destroy(ctx); + ctx = IntPtr.Zero; + } + } + } +} diff --git a/bindings/csharp/Device.cs b/bindings/csharp/Device.cs new file mode 100644 index 0000000..8d7fa82 --- /dev/null +++ b/bindings/csharp/Device.cs @@ -0,0 +1,262 @@ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2015 Analog Devices, Inc. + * Author: Paul Cercueil <paul.cercueil@analog.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace iio +{ + /// <summary><see cref="iio.Device"/> class: + /// Contains the representation of an IIO device.</summary> + public class Device + { + private class DeviceAttr : Attr + { + private IntPtr dev; + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_attr_read(IntPtr dev, [In()] string name, [Out()] StringBuilder val, uint len); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_attr_write(IntPtr dev, [In()] string name, [In()] string val); + + public DeviceAttr(IntPtr dev, string name) : base(name) + { + this.dev = dev; + } + + public override string read() + { + StringBuilder builder = new StringBuilder(1024); + int err = iio_device_attr_read(dev, name, builder, 1024); + if (err < 0) + throw new Exception("Unable to read device attribute " + err); + return builder.ToString(); + } + + public override void write(string str) + { + int err = iio_device_attr_write(dev, name, str); + if (err < 0) + throw new Exception("Unable to write device attribute " + err); + } + } + + private class DeviceDebugAttr : Attr + { + private IntPtr dev; + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_debug_attr_read(IntPtr dev, [In()] string name, [Out()] StringBuilder val, uint len); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_debug_attr_write(IntPtr dev, [In()] string name, [In()] string val); + + public DeviceDebugAttr(IntPtr dev, string name) : base(name) + { + this.dev = dev; + } + + public override string read() + { + StringBuilder builder = new StringBuilder(1024); + int err = iio_device_debug_attr_read(dev, name, builder, 1024); + if (err < 0) + throw new Exception("Unable to read debug attribute " + err); + return builder.ToString(); + } + + public override void write(string str) + { + int err = iio_device_debug_attr_write(dev, name, str); + if (err < 0) + throw new Exception("Unable to write debug attribute " + err); + } + } + + private Context ctx; + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_device_get_id(IntPtr dev); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_device_get_name(IntPtr dev); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_device_get_channels_count(IntPtr dev); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_device_get_channel(IntPtr dev, uint index); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_device_get_attrs_count(IntPtr dev); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint iio_device_get_debug_attrs_count(IntPtr dev); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_device_get_attr(IntPtr dev, uint index); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_device_get_debug_attr(IntPtr dev, uint index); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_get_trigger(IntPtr dev, IntPtr triggerptr); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_set_trigger(IntPtr dev, IntPtr trigger); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_get_sample_size(IntPtr dev); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_reg_write(IntPtr dev, uint addr, uint value); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_device_reg_read(IntPtr dev, uint addr, ref uint value); + + internal IntPtr dev; + + /// <summary>An identifier of this device.</summary> + /// <remarks>The identifier is only valid in this IIO context</remarks> + public readonly string id; + + /// <summary>The name of this device.</summary> + public readonly string name; + + /// <summary>A <c>list</c> of all the attributes that this device has.</summary> + public readonly List<Attr> attrs; + + /// <summary>A <c>list</c> of all the debug attributes that this device has.</summary> + public readonly List<Attr> debug_attrs; + + /// <summary>A <c>list</c> of all the <see cref="iio.Channel"/> objects that this device possesses.</summary> + public readonly List<Channel> channels; + + internal Device(Context ctx, IntPtr dev) + { + this.ctx = ctx; + this.dev = dev; + channels = new List<Channel>(); + attrs = new List<Attr>(); + debug_attrs = new List<Attr>(); + + uint nb_channels = iio_device_get_channels_count(dev), + nb_attrs = iio_device_get_attrs_count(dev), + nb_debug_attrs = iio_device_get_debug_attrs_count(dev); + + for (uint i = 0; i < nb_channels; i++) + channels.Add(new Channel(iio_device_get_channel(dev, i))); + + for (uint i = 0; i < nb_attrs; i++) + attrs.Add(new DeviceAttr(dev, Marshal.PtrToStringAnsi(iio_device_get_attr(dev, i)))); + for (uint i = 0; i < nb_debug_attrs; i++) + debug_attrs.Add(new DeviceDebugAttr(dev, Marshal.PtrToStringAnsi(iio_device_get_debug_attr(dev, i)))); + + id = Marshal.PtrToStringAnsi(iio_device_get_id(dev)); + + IntPtr name_ptr = iio_device_get_name(dev); + if (name_ptr == IntPtr.Zero) + name = ""; + else + name = Marshal.PtrToStringAnsi(name_ptr); + } + + /// <summary>Get the <see cref="iio.Channel"/> object of the specified name.</summary> + /// <param name="name">Name or ID of the channel to look for</param> + /// <exception cref="System.Exception">The IIO device with the specified + /// name or ID could not be found in the current context.</exception> + public Channel get_channel(string name) + { + foreach (Channel each in channels) { + if (each.name.CompareTo(name) == 0 || + each.id.CompareTo(name) == 0) + return each; + } + + throw new Exception("Channel " + name + " not found"); + } + + /// <summary>Affect a trigger to this device.</summary> + /// <param name="trig">A valid instance of the <see cref="iio.Trigger"/> class.</param> + /// <exception cref="System.Exception">The trigger could not be set.</exception> + public void set_trigger(Trigger trig) + { + int err = iio_device_set_trigger(this.dev, trig == null ? IntPtr.Zero : trig.dev); + if (err < 0) + throw new Exception("Unable to set trigger: err=" + err); + } + + /// <summary>Get the current trigger affected to this device.</summary> + /// <returns>An instance of the <see cref="iio.Trigger"/> class.</returns> + /// <exception cref="System.Exception">The instance could not be retrieved.</exception> + public Trigger get_trigger() + { + IntPtr ptr = (IntPtr)0; + int err = iio_device_get_trigger(this.dev, ptr); + if (err < 0) + throw new Exception("Unable to get trigger: err=" + err); + + ptr = Marshal.ReadIntPtr(ptr); + + foreach (Trigger trig in ctx.devices) { + if (trig.dev == ptr) + return trig; + } + + return null; + } + + /// <summary>Get the current sample size of the device.</summary> + /// <remarks>The sample size varies each time channels get enabled or disabled.</remarks> + /// <exception cref="System.Exception">Internal error. Please report any bug.</exception> + public uint get_sample_size() + { + int ret = iio_device_get_sample_size(dev); + if (ret < 0) + throw new Exception("Internal error. Please report any bug."); + return (uint) ret; + } + /// <summary>Set a value to one register of this device.</summary> + /// <param name="addr">The address of the register concerned.</param> + /// <param name="value">The value that will be used for this register.</param> + /// <exception cref="System.Exception">The register could not be written.</exception> + public void reg_write(uint addr, uint value) + { + int err = iio_device_reg_write(dev, addr, value); + if (err < 0) + throw new Exception("Unable to write register"); + } + + /// <summary>Read the content of a register of this device.</summary> + /// <param name="addr">The address of the register concerned.</param> + /// <exception cref="System.Exception">The register could not be read.</exception> + public uint reg_read(uint addr) + { + uint value = 0; + int err = iio_device_reg_read(dev, addr, ref value); + if (err < 0) + throw new Exception("Unable to read register"); + return value; + } + } +} diff --git a/bindings/csharp/IOBuffer.cs b/bindings/csharp/IOBuffer.cs new file mode 100644 index 0000000..1697f6e --- /dev/null +++ b/bindings/csharp/IOBuffer.cs @@ -0,0 +1,143 @@ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2015 Analog Devices, Inc. + * Author: Paul Cercueil <paul.cercueil@analog.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace iio +{ + /// <summary><see cref="iio.IOBuffer"/> class: + /// The class used for all I/O operations.</summary> + public class IOBuffer : IDisposable + { + private bool circular_buffer_pushed; + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_device_create_buffer(IntPtr dev, uint samples_count, + [MarshalAs(UnmanagedType.I1)] bool circular); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void iio_buffer_destroy(IntPtr buf); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_buffer_refill(IntPtr buf); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int iio_buffer_push_partial(IntPtr buf, uint samples_count); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_buffer_start(IntPtr buf); + + [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr iio_buffer_end(IntPtr buf); + + internal IntPtr buf; + + /// <summary>The size of this buffer, in samples.</summary> + public readonly uint samples_count; + + /// <summary>If <c>true</c>, the buffer is circular.</summary> + public readonly bool circular; + + /// <summary>Initializes a new instance of the <see cref="iio.IOBuffer"/> class.</summary> + /// <param name="dev">The <see cref="iio.Device"/> object that represents the device + /// where the I/O operations will be performed.</param> + /// <param name="samples_count">The size of the buffer, in samples.</param> + /// <param name="circular">If set to <c>true</c>, the buffer is circular.</param> + /// <exception cref="System.Exception">The buffer could not be created.</exception> + public IOBuffer(Device dev, uint samples_count, bool circular = false) + { + this.samples_count = samples_count; + this.circular = circular; + this.circular_buffer_pushed = false; + + buf = iio_device_create_buffer(dev.dev, samples_count, circular); + if (buf == IntPtr.Zero) + throw new Exception("Unable to create buffer"); + } + + ~IOBuffer() + { + if (buf != IntPtr.Zero) + Dispose(false); + } + + /// <summary>Fetch a new set of samples from the hardware.</summary> + /// <exception cref="System.Exception">The buffer could not be refilled.</exception> + public void refill() + { + int err = iio_buffer_refill(this.buf); + if (err < 0) + throw new Exception("Unable to refill buffer: err=" + err); + } + + /// <summary>Submit the samples contained in this buffer to the hardware.</summary> + /// <exception cref="System.Exception">The buffer could not be pushed.</exception> + public void push(uint samples_count) + { + if (circular && circular_buffer_pushed) + throw new Exception("Circular buffer already pushed\n"); + + int err = iio_buffer_push_partial(this.buf, samples_count); + if (err < 0) + throw new Exception("Unable to push buffer: err=" + err); + circular_buffer_pushed = true; + } + + public void push() + { + push(this.samples_count); + } + + /// <summary>Releases all resource used by the <see cref="iio.IOBuffer"/> object.</summary> + /// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="iio.IOBuffer"/>. The + /// <see cref="Dispose"/> method leaves the <see cref="iio.IOBuffer"/> in an unusable state. After calling + /// <see cref="Dispose"/>, you must release all references to the <see cref="iio.IOBuffer"/> so the garbage + /// collector can reclaim the memory that the <see cref="iio.IOBuffer"/> was occupying.</remarks> + public void Dispose() + { + Dispose(true); + } + + private void Dispose(bool clean) + { + if (buf != IntPtr.Zero) + { + if (clean) + GC.SuppressFinalize(this); + iio_buffer_destroy(buf); + buf = IntPtr.Zero; + } + } + + /// <summary>Copy the given array of samples inside the <see cref="iio.IOBuffer"/> object.</summary> + /// <param name="array">A <c>byte</c> array containing the samples that should be written.</param> + /// <remarks>The number of samples written will not exceed the size of the buffer.</remarks> + public void fill(byte[] array) + { + int length = (int) iio_buffer_end(buf) - (int) iio_buffer_start(buf); + if (length > array.Length) + length = array.Length; + Marshal.Copy(array, 0, iio_buffer_start(buf), length); + } + } +} diff --git a/bindings/csharp/Trigger.cs b/bindings/csharp/Trigger.cs new file mode 100644 index 0000000..4614143 --- /dev/null +++ b/bindings/csharp/Trigger.cs @@ -0,0 +1,67 @@ +/* + * libiio - Library for interfacing industrial I/O (IIO) devices + * + * Copyright (C) 2015 Analog Devices, Inc. + * Author: Paul Cercueil <paul.cercueil@analog.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace iio +{ + /// <summary><see cref="iio.Trigger"/> class: + /// Contains the representation of an IIO device that can act as a trigger.</summary> + public class Trigger : Device + { + internal Trigger(Context ctx, IntPtr ptr) : base(ctx, ptr) { } + + /// <summary>Configure a new frequency for this trigger.</summary> + /// <exception cref="System.Exception">The new frequency could not be set.</exception> + public void set_rate(ulong rate) + { + foreach (Attr each in attrs) + if (each.name.Equals("frequency")) + { + each.write((long) rate); + return; + } + throw new Exception("Trigger has no frequency?"); + } + + /// <summary>Get the currently configured frequency of this trigger.</summary> + /// <exception cref="System.Exception">The configured frequency could not be obtained.</exception> + public ulong get_rate() + { + foreach (Attr each in attrs) + if (each.name.Equals("frequency")) + return (ulong) each.read_long(); + throw new Exception("Trigger has no frequency?"); + } + + public new void set_trigger(Trigger trig) + { + throw new InvalidComObjectException("Device is already a trigger"); + } + + public new Trigger get_trigger() + { + throw new InvalidComObjectException("Device is already a trigger"); + } + } +} diff --git a/bindings/csharp/examples/ExampleProgram.cs b/bindings/csharp/examples/ExampleProgram.cs new file mode 100644 index 0000000..f33e381 --- /dev/null +++ b/bindings/csharp/examples/ExampleProgram.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using iio; + +namespace IIOCSharp +{ + class ExampleProgram + { + static void Main(string[] args) + { + Context ctx = new Context("10.44.2.241"); + if (ctx == null) + { + Console.WriteLine("Unable to create IIO context"); + return; + } + + Console.WriteLine("IIO context created: " + ctx.name); + Console.WriteLine("IIO context description: " + ctx.description); + + Console.WriteLine("IIO context has " + ctx.devices.Count + " devices:"); + foreach (Device dev in ctx.devices) { + Console.WriteLine("\t" + dev.id + ": " + dev.name); + + if (dev is Trigger) + { + Console.WriteLine("Found trigger! Rate=" + ((Trigger) dev).get_rate()); + } + + Console.WriteLine("\t\t" + dev.channels.Count + " channels found:"); + + foreach (Channel chn in dev.channels) + { + string type = "input"; + if (chn.output) + type = "output"; + Console.WriteLine("\t\t\t" + chn.id + ": " + chn.name + " (" + type + ")"); + + if (chn.attrs.Count == 0) + continue; + + Console.WriteLine("\t\t\t" + chn.attrs.Count + " channel-specific attributes found:"); + foreach (Attr attr in chn.attrs) + { + Console.WriteLine("\t\t\t\t" + attr.name); + if (attr.name.CompareTo("frequency") == 0) + { + Console.WriteLine("Attribute content: " + attr.read()); + } + } + + } + + /* If we find cf-ad9361-lpc, try to read a few bytes from the first channel */ + if (dev.name.CompareTo("cf-ad9361-lpc") == 0) + { + Channel chn = dev.channels[0]; + chn.enable(); + IOBuffer buf = new IOBuffer(dev, 0x8000); + buf.refill(); + + Console.WriteLine("Read " + chn.read(buf).Length + " bytes from hardware"); + buf.Dispose(); + } + + if (dev.attrs.Count == 0) + continue; + + Console.WriteLine("\t\t" + dev.attrs.Count + " device-specific attributes found:"); + foreach (Attr attr in dev.attrs) + Console.WriteLine("\t\t\t" + attr.name); + + } + + /* Wait for user input */ + Console.ReadLine(); + } + } +} diff --git a/bindings/csharp/key.snk b/bindings/csharp/key.snk Binary files differnew file mode 100644 index 0000000..fc21149 --- /dev/null +++ b/bindings/csharp/key.snk diff --git a/bindings/csharp/libiio-sharp.dll.config.cmakein b/bindings/csharp/libiio-sharp.dll.config.cmakein new file mode 100644 index 0000000..c9ef9bb --- /dev/null +++ b/bindings/csharp/libiio-sharp.dll.config.cmakein @@ -0,0 +1,3 @@ +<configuration> + <dllmap dll="libiio.dll" target="libiio.so.@LIBIIO_VERSION_MAJOR@"/> +</configuration> diff --git a/bindings/csharp/libiio-sharp.pc.cmakein b/bindings/csharp/libiio-sharp.pc.cmakein new file mode 100644 index 0000000..5e6fd22 --- /dev/null +++ b/bindings/csharp/libiio-sharp.pc.cmakein @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_PREFIX@/lib + +Name: libiio-cs +Description: CLI bindings for libiio +Version: @VERSION@ + +Requires: +Libs: -r:${libdir}/cli/libiio-sharp-@VERSION@/libiio-sharp.dll diff --git a/bindings/matlab/CMakeLists.txt b/bindings/matlab/CMakeLists.txt new file mode 100644 index 0000000..4eea7d5 --- /dev/null +++ b/bindings/matlab/CMakeLists.txt @@ -0,0 +1,26 @@ +find_program( + MATLAB_EXECUTABLE + NAMES matlab + DOC "Matlab main program" +) +mark_as_advanced(MATLAB_EXECUTABLE) + +option(WITH_MATLAB_BINDINGS_API "Enable MATLAB bindings API" ON) + +if (MATLAB_EXECUTABLE AND NOT SKIP_INSTALL_ALL) + option(MATLAB_BINDINGS "Install MATLAB bindings" ON) + + if (MATLAB_BINDINGS) + install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/libiio" + PATTERN "CMakeLists.txt" EXCLUDE + ) + install( + CODE "execute_process( + COMMAND ${MATLAB_EXECUTABLE} -nodesktop + -nodisplay -r \"cd('${CMAKE_INSTALL_PREFIX}/share/libiio/matlab');iio_installer_script;exit;\" + OUTPUT_QUIET)") + set(WITH_MATLAB_BINDINGS_API ON CACHE BOOL "" FORCE) + endif() +endif() diff --git a/bindings/matlab/iio-wrapper.h b/bindings/matlab/iio-wrapper.h new file mode 100644 index 0000000..ce2b046 --- /dev/null +++ b/bindings/matlab/iio-wrapper.h @@ -0,0 +1,46 @@ +#ifndef MATLAB_LOADLIBRARY +#define MATLAB_LOADLIBRARY +#include <iio.h> + +#ifndef __api +#define __api +#endif + +struct iio_scan_block; + +/** @brief Create a scan block +* @param backend A NULL-terminated string containing the backend to use for +* scanning. If NULL, all the available backends are used. +* @param flags Unused for now. Set to 0. +* @return on success, a pointer to a iio_scan_block structure +* @return On failure, NULL is returned and errno is set appropriately */ +__api struct iio_scan_block * iio_create_scan_block( + const char *backend, unsigned int flags); + + +/** @brief Destroy the given scan block +* @param ctx A pointer to an iio_scan_block structure +* +* <b>NOTE:</b> After that function, the iio_scan_block pointer shall be invalid. */ +__api void iio_scan_block_destroy(struct iio_scan_block *blk); + + +/** @brief Enumerate available contexts via scan block +* @param blk A pointer to a iio_scan_block structure. +* @returns On success, the number of contexts found. +* @returns On failure, a negative error number. +*/ +__api ssize_t iio_scan_block_scan(struct iio_scan_block *blk); + + +/** @brief Get the iio_context_info for a particular context +* @param blk A pointer to an iio_scan_block structure +* @param index The index corresponding to the context. +* @return A pointer to the iio_context_info for the context +* @returns On success, a pointer to the specified iio_context_info +* @returns On failure, NULL is returned and errno is set appropriately +*/ +__api struct iio_context_info *iio_scan_block_get_info( + struct iio_scan_block *blk, unsigned int index); + +#endif diff --git a/bindings/matlab/iio_installer_script.m b/bindings/matlab/iio_installer_script.m new file mode 100644 index 0000000..1276729 --- /dev/null +++ b/bindings/matlab/iio_installer_script.m @@ -0,0 +1,17 @@ +function installer_script(varargin) + if nargin > 0 + install = varargin{1}; % use the command line arguement + else + install = true; % assume install + end + thisDir = fileparts(mfilename('fullpath')); % path to this script + + if install + pathfunc = @addpath; % add paths for installation + else + pathfunc = @rmpath; % remove paths for uninstall + end + + pathfunc(thisDir); + savepath; +end diff --git a/bindings/matlab/iio_sys_obj.m b/bindings/matlab/iio_sys_obj.m new file mode 100644 index 0000000..1f8380f --- /dev/null +++ b/bindings/matlab/iio_sys_obj.m @@ -0,0 +1,474 @@ +% Copyright 2014-15(c) Analog Devices, Inc. +% +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without modification, +% are permitted provided that the following conditions are met: +% - Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% - Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in +% the documentation and/or other materials provided with the +% distribution. +% - Neither the name of Analog Devices, Inc. nor the names of its +% contributors may be used to endorse or promote products derived +% from this software without specific prior written permission. +% - The use of this software may or may not infringe the patent rights +% of one or more patent holders. This license does not release you +% from the requirement that you obtain separate licenses from these +% patent holders to use this software. +% - Use of the software either in source or binary form or filter designs +% resulting from the use of this software, must be connected to, run +% on or loaded to an Analog Devices Inc. component. +% +% THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +% INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +% PARTICULAR PURPOSE ARE DISCLAIMED. +% +% IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY +% RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +% THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +classdef iio_sys_obj < matlab.System & matlab.system.mixin.Propagates ... + & matlab.system.mixin.CustomIcon + % iio_sys_obj System Object block for IIO devices + + properties (Nontunable) + % Public, non-tunable properties. + + %ip_address IP address + ip_address = ''; + + %dev_name Device name + dev_name = ''; + + %in_ch_no Number of input data channels + in_ch_no = 0; + + %in_ch_size Input data channel size [samples] + in_ch_size = 8192; + + %out_ch_no Number of output data channels + out_ch_no = 0; + + %out_ch_size Output data channel size [samples] + out_ch_size = 8192; + end + + properties (Access = protected) + % Protected class properties. + + %iio_dev_cfg Device configuration structure + iio_dev_cfg = []; + end + + properties (Access = private) + % Private class properties. + + %libiio_data_in_dev libiio IIO interface object for the input data device + libiio_data_in_dev = {}; + + %libiio_data_out_dev libiio IIO interface object for the output data device + libiio_data_out_dev = {}; + + %libiio_ctrl_dev libiio IIO interface object for the control device + libiio_ctrl_dev = {}; + + %sys_obj_initialized Holds the initialization status of the system object + sys_obj_initialized = 0; + end + + properties (DiscreteState) + % Discrete state properties. + + %num_cfg_in Numeric type input control channels data + num_cfg_in; + + %str_cfg_in String type input control channels data + str_cfg_in; + end + + methods + %% Constructor + function obj = iio_sys_obj(varargin) + % Construct the libiio interface objects + obj.libiio_data_in_dev = libiio_if(); + obj.libiio_data_out_dev = libiio_if(); + obj.libiio_ctrl_dev = libiio_if(); + + % Support name-value pair arguments when constructing the object. + setProperties(obj,nargin,varargin{:}); + end + end + + methods (Access = protected) + %% Utility functions + + function config = getObjConfig(obj) + % Read the selected device configuration + + % Open the configuration file + fname = sprintf('%s.cfg', obj.dev_name); + fp_cfg = fopen(fname); + if(fp_cfg < 0) + config = {}; + return; + end + + % Build the object configuration structure + config = struct('data_in_device', '',... % Pointer to the data input device + 'data_out_device', '',... % Pointer to the data output device + 'ctrl_device', '',... % Pointer to the control device + 'cfg_ch', [],... % Configuration channels list + 'mon_ch', []); % Monitoring channels list + + % Build the configuration/monitoring channels structure + ch_cfg = struct('port_name', '',... % Name of the port to be displayed on the object block + 'port_attr', '',... % Associated device attribute name + 'ctrl_dev_name', '',... % Control device name + 'ctrl_dev', 0); % Pointer to the control device object + + % Read the object's configuration + while(~feof(fp_cfg)) + line = fgets(fp_cfg); + if(strfind(line,'#')) + continue; + end + if(~isempty(strfind(line, 'channel'))) + % Get the associated configuration/monitoring channels + idx = strfind(line, '='); + line = line(idx+1:end); + line = strsplit(line, ','); + ch_cfg.port_name = strtrim(line{1}); + ch_cfg.port_attr = strtrim(line{3}); + if(length(line) > 4) + ch_cfg.ctrl_dev_name = strtrim(line{4}); + else + ch_cfg.ctrl_dev_name = 'ctrl_device'; + end + if(strcmp(strtrim(line{2}), 'IN')) + config.cfg_ch = [config.cfg_ch ch_cfg]; + elseif(strcmp(strtrim(line{2}), 'OUT')) + config.mon_ch = [config.mon_ch ch_cfg]; + end + elseif(~isempty(strfind(line, 'data_in_device'))) + % Get the associated data input device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_in_device = tmp; + elseif(~isempty(strfind(line, 'data_out_device'))) + % Get the associated data output device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_out_device = tmp; + elseif(~isempty(strfind(line, 'ctrl_device'))) + % Get the associated control device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.ctrl_device = tmp; + end + end + fclose(fp_cfg); + end + + end + + methods (Access = protected) + %% Common functions + function setupImpl(obj) + % Implement tasks that need to be performed only once. + + % Set the initialization status to fail + obj.sys_obj_initialized = 0; + + % Read the object's configuration from the associated configuration file + obj.iio_dev_cfg = getObjConfig(obj); + if(isempty(obj.iio_dev_cfg)) + msgbox('Could not read device configuration!', 'Error','error'); + return; + end + + % Initialize discrete-state properties. + obj.num_cfg_in = zeros(1, length(obj.iio_dev_cfg.cfg_ch)); + obj.str_cfg_in = zeros(length(obj.iio_dev_cfg.cfg_ch), 64); + + % Initialize the libiio data input device + if(obj.in_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_in_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_in_device, 'OUT', ... + obj.in_ch_no, obj.in_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio data output device + if(obj.out_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_out_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_out_device, 'IN', ... + obj.out_ch_no, obj.out_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio control device + if(~isempty(obj.iio_dev_cfg.ctrl_device)) + [ret, err_msg, msg_log] = init(obj.libiio_ctrl_dev, obj.ip_address, ... + obj.iio_dev_cfg.ctrl_device, '', ... + 0, 0); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Assign the control device for each monitoring channel + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + if(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Assign the control device for each configuration channel + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Set the initialization status to success + obj.sys_obj_initialized = 1; + end + + function releaseImpl(obj) + % Release any resources used by the system object. + obj.iio_dev_cfg = {}; + delete(obj.libiio_data_in_dev); + delete(obj.libiio_data_out_dev); + delete(obj.libiio_ctrl_dev); + end + + function varargout = stepImpl(obj, varargin) + % Implement the system object's processing flow. + varargout = cell(1, obj.out_ch_no + length(obj.iio_dev_cfg.mon_ch)); + if(obj.sys_obj_initialized == 0) + return; + end + + % Implement the device configuration flow + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(~isempty(varargin{i + obj.in_ch_no})) + if(length(varargin{i + obj.in_ch_no}) == 1) + new_data = (varargin{i + obj.in_ch_no} ~= obj.num_cfg_in(i)); + else + new_data = ~strncmp(char(varargin{i + obj.in_ch_no}'), char(obj.str_cfg_in(i,:)), length(varargin{i + obj.in_ch_no})); + end + if(new_data == 1) + if(length(varargin{i + obj.in_ch_no}) == 1) + obj.num_cfg_in(i) = varargin{i + obj.in_ch_no}; + str = num2str(obj.num_cfg_in(i)); + else + for j = 1:length(varargin{i + obj.in_ch_no}) + obj.str_cfg_in(i,j) = varargin{i + obj.in_ch_no}(j); + end + obj.str_cfg_in(i,j+1) = 0; + str = char(obj.str_cfg_in(i,:)); + end + writeAttributeString(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev, obj.iio_dev_cfg.cfg_ch(i).port_attr, str); + end + end + end + + % Implement the data transmit flow + writeData(obj.libiio_data_in_dev, varargin); + + % Implement the data capture flow + [~, data] = readData(obj.libiio_data_out_dev); + for i = 1 : obj.out_ch_no + varargout{i} = data{i}; + end + + % Implement the parameters monitoring flow + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + [~, val] = readAttributeDouble(obj.iio_dev_cfg.mon_ch(i).ctrl_dev, obj.iio_dev_cfg.mon_ch(i).port_attr); + varargout{obj.out_ch_no + i} = val; + end + + + end + + function resetImpl(obj) + % Initialize discrete-state properties. + obj.num_cfg_in = zeros(1, length(obj.iio_dev_cfg.cfg_ch)); + obj.str_cfg_in = zeros(length(obj.iio_dev_cfg.cfg_ch), 64); + end + + function num = getNumInputsImpl(obj) + % Get number of inputs. + num = obj.in_ch_no; + + config = getObjConfig(obj); + if(~isempty(config)) + num = num + length(config.cfg_ch); + end + end + + function varargout = getInputNamesImpl(obj) + % Get input names + + % Get the number of input data channels + data_ch_no = obj.in_ch_no; + + % Get number of control channels + cfg_ch_no = 0; + config = getObjConfig(obj); + if(~isempty(config)) + cgf_ch_no = length(config.cfg_ch); + end + + if(data_ch_no + cgf_ch_no ~= 0) + varargout = cell(1, data_ch_no + cgf_ch_no); + for i = 1 : data_ch_no + varargout{i} = sprintf('DATA_IN%d', i); + end + for i = data_ch_no + 1 : data_ch_no + cgf_ch_no + varargout{i} = config.cfg_ch(i - data_ch_no).port_name; + end + else + varargout = {}; + end + end + + function num = getNumOutputsImpl(obj) + % Get number of outputs. + num = obj.out_ch_no; + + config = getObjConfig(obj); + if(~isempty(config)) + num = num + length(config.mon_ch); + end + end + + function varargout = getOutputNamesImpl(obj) + % Get output names + + % Get the number of output data channels + data_ch_no = obj.out_ch_no; + + % Get number of monitoring channels + mon_ch_no = 0; + config = getObjConfig(obj); + if(~isempty(config)) + mon_ch_no = length(config.mon_ch); + end + + if(data_ch_no + mon_ch_no ~= 0) + varargout = cell(1, data_ch_no + mon_ch_no); + for i = 1 : data_ch_no + varargout{i} = sprintf('DATA_OUT%d', i); + end + for i = data_ch_no + 1 : data_ch_no + mon_ch_no + varargout{i} = config.mon_ch(i - data_ch_no).port_name; + end + else + varargout = {}; + end + end + + function varargout = isOutputFixedSizeImpl(obj) + % Get outputs fixed size. + varargout = cell(1, getNumOutputs(obj)); + for i = 1 : getNumOutputs(obj) + varargout{i} = true; + end + end + + function varargout = getOutputDataTypeImpl(obj) + % Get outputs data types. + varargout = cell(1, getNumOutputs(obj)); + for i = 1 : getNumOutputs(obj) + varargout{i} = 'double'; + end + end + + function varargout = isOutputComplexImpl(obj) + % Get outputs data types. + varargout = cell(1, getNumOutputs(obj)); + for i = 1 : getNumOutputs(obj) + varargout{i} = false; + end + end + + function varargout = getOutputSizeImpl(obj) + % Implement if input size does not match with output size. + varargout = cell(1, getNumOutputs(obj)); + for i = 1:obj.out_ch_no + varargout{i} = [obj.out_ch_size 1]; + end + for i = obj.out_ch_no + 1 : length(varargout) + varargout{i} = [1 1]; + end + end + + function icon = getIconImpl(obj) + % Define a string as the icon for the System block in Simulink. + if(~isempty(obj.dev_name)) + icon = obj.dev_name; + else + icon = mfilename('class'); + end + end + + %% Backup/restore functions + function s = saveObjectImpl(obj) + % Save private, protected, or state properties in a + % structure s. This is necessary to support Simulink + % features, such as SimState. + end + + function loadObjectImpl(obj, s, wasLocked) + % Read private, protected, or state properties from + % the structure s and assign it to the object obj. + end + + %% Simulink functions + function z = getDiscreteStateImpl(obj) + % Return structure of states with field names as + % DiscreteState properties. + z = struct([]); + end + end + + methods(Static, Access = protected) + %% Simulink customization functions + function header = getHeaderImpl(obj) + % Define header for the System block dialog box. + header = matlab.system.display.Header(mfilename('class')); + end + + function group = getPropertyGroupsImpl(obj) + % Define section for properties in System block dialog box. + group = matlab.system.display.Section(mfilename('class')); + end + end +end diff --git a/bindings/matlab/iio_sys_obj_matlab.m b/bindings/matlab/iio_sys_obj_matlab.m new file mode 100644 index 0000000..572ec03 --- /dev/null +++ b/bindings/matlab/iio_sys_obj_matlab.m @@ -0,0 +1,350 @@ +% Copyright 2014(c) Analog Devices, Inc. +% +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without modification, +% are permitted provided that the following conditions are met: +% - Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% - Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in +% the documentation and/or other materials provided with the +% distribution. +% - Neither the name of Analog Devices, Inc. nor the names of its +% contributors may be used to endorse or promote products derived +% from this software without specific prior written permission. +% - The use of this software may or may not infringe the patent rights +% of one or more patent holders. This license does not release you +% from the requirement that you obtain separate licenses from these +% patent holders to use this software. +% - Use of the software either in source or binary form or filter designs +% resulting from the use of this software, must be connected to, run +% on or loaded to an Analog Devices Inc. component. +% +% THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +% INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +% PARTICULAR PURPOSE ARE DISCLAIMED. +% +% IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY +% RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +% THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +classdef iio_sys_obj_matlab + % iio_sys_obj System Object block for IIO devices + + properties (Access = public) + % Public, non-tunable properties. + + %ip_address IP address + ip_address = ''; + + %dev_name Device name + dev_name = ''; + + %in_ch_no Number of input data channels + in_ch_no = 0; + + %in_ch_size Input data channel size [samples] + in_ch_size = 8192; + + %out_ch_no Number of output data channels + out_ch_no = 0; + + %out_ch_size Output data channel size [samples] + out_ch_size = 8192; + end + + properties (Access = public) + % Protected class properties. + + %iio_dev_cfg Device configuration structure + iio_dev_cfg = []; + end + + properties (Access = private) + % Private class properties. + + %libiio_data_in_dev libiio IIO interface object for the input data device + libiio_data_in_dev = {}; + + %libiio_data_out_dev libiio IIO interface object for the output data device + libiio_data_out_dev = {}; + + %libiio_ctrl_dev libiio IIO interface object for the control device + libiio_ctrl_dev = {}; + + %sys_obj_initialized Holds the initialization status of the system object + sys_obj_initialized = 0; + end + + properties (Access = private) + % Discrete state properties. + + %num_cfg_in Numeric type input control channels data + num_cfg_in; + + %str_cfg_in String type input control channels data + str_cfg_in; + end + + methods + %% Constructor + function obj = iio_sys_obj_matlab(varargin) + % Construct the libiio interface objects + obj.libiio_data_in_dev = libiio_if(); + obj.libiio_data_out_dev = libiio_if(); + obj.libiio_ctrl_dev = libiio_if(); + end + end + + methods (Access = protected) + %% Utility functions + + function config = getObjConfig(obj) + % Read the selected device configuration + + % Open the configuration file + fname = sprintf('%s.cfg', obj.dev_name); + fp_cfg = fopen(fname); + if(fp_cfg < 0) + config = {}; + return; + end + + % Build the object configuration structure + config = struct('data_in_device', '',... % Pointer to the data input device + 'data_out_device', '',... % Pointer to the data output device + 'ctrl_device', '',... % Pointer to the control device + 'cfg_ch', [],... % Configuration channels list + 'mon_ch', [],... % Monitoring channels list + 'in_ch_names', [],... % Configuration channels names + 'out_ch_names', []); % Monitoring channels names + config.in_ch_names = {}; + config.out_ch_names = {}; + + % Build the configuration/monitoring channels structure + ch_cfg = struct('port_name', '',... % Name of the port to be displayed on the object block + 'port_attr', '',... % Associated device attribute name + 'ctrl_dev_name', '',... % Control device name + 'ctrl_dev', 0); % Pointer to the control device object + + % Read the object's configuration + while(~feof(fp_cfg)) + line = fgets(fp_cfg); + if(strfind(line,'#')) + continue; + end + if(~isempty(strfind(line, 'channel'))) + % Get the associated configuration/monitoring channels + idx = strfind(line, '='); + line = line(idx+1:end); + line = strsplit(line, ','); + ch_cfg.port_name = strtrim(line{1}); + ch_cfg.port_attr = strtrim(line{3}); + if(length(line) > 4) + ch_cfg.ctrl_dev_name = strtrim(line{4}); + else + ch_cfg.ctrl_dev_name = 'ctrl_device'; + end + if(strcmp(strtrim(line{2}), 'IN')) + config.cfg_ch = [config.cfg_ch ch_cfg]; + config.in_ch_names = [config.in_ch_names ch_cfg.port_name]; + elseif(strcmp(strtrim(line{2}), 'OUT')) + config.mon_ch = [config.mon_ch ch_cfg]; + config.out_ch_names = [config.out_ch_names ch_cfg.port_name]; + end + elseif(~isempty(strfind(line, 'data_in_device'))) + % Get the associated data input device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_in_device = tmp; + elseif(~isempty(strfind(line, 'data_out_device'))) + % Get the associated data output device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.data_out_device = tmp; + elseif(~isempty(strfind(line, 'ctrl_device'))) + % Get the associated control device + idx = strfind(line, '='); + tmp = line(idx+1:end); + tmp = strtrim(tmp); + config.ctrl_device = tmp; + end + end + fclose(fp_cfg); + end + + end + + methods (Access = public) + %% Helper functions + function ret = getInChannel(obj, channelName) + % Returns the index of a named input channel + ret = obj.in_ch_no + find(strcmp(obj.iio_dev_cfg.in_ch_names, channelName)); + end + + function ret = getOutChannel(obj, channelName) + % Returns the index of a named output channel + ret = obj.out_ch_no + find(strcmp(obj.iio_dev_cfg.out_ch_names, channelName)); + end + + %% Common functions + function ret = setupImpl(obj) + % Implement tasks that need to be performed only once. + + % Set the initialization status to fail + obj.sys_obj_initialized = 0; + + % Read the object's configuration from the associated configuration file + obj.iio_dev_cfg = getObjConfig(obj); + if(isempty(obj.iio_dev_cfg)) + msgbox('Could not read device configuration!', 'Error','error'); + return; + end + + % Initialize discrete-state properties. + obj.num_cfg_in = zeros(1, length(obj.iio_dev_cfg.cfg_ch)); + obj.str_cfg_in = zeros(length(obj.iio_dev_cfg.cfg_ch), 64); + + % Initialize the libiio data input device + if(obj.in_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_in_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_in_device, 'OUT', ... + obj.in_ch_no, obj.in_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio data output device + if(obj.out_ch_no ~= 0) + [ret, err_msg, msg_log] = init(obj.libiio_data_out_dev, obj.ip_address, ... + obj.iio_dev_cfg.data_out_device, 'IN', ... + obj.out_ch_no, obj.out_ch_size); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Initialize the libiio control device + if(~isempty(obj.iio_dev_cfg.ctrl_device)) + [ret, err_msg, msg_log] = init(obj.libiio_ctrl_dev, obj.ip_address, ... + obj.iio_dev_cfg.ctrl_device, '', ... + 0, 0); + fprintf('%s', msg_log); + if(ret < 0) + msgbox(err_msg, 'Error','error'); + return; + end + end + + % Assign the control device for each monitoring channel + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + if(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.mon_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.mon_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Assign the control device for each configuration channel + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_in_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_in_dev; + elseif(strcmp(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev_name, 'data_out_device')) + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_data_out_dev; + else + obj.iio_dev_cfg.cfg_ch(i).ctrl_dev = obj.libiio_ctrl_dev; + end + end + + % Set the initialization status to success + obj.sys_obj_initialized = 1; + ret = obj; + end + + function releaseImpl(obj) + % Release any resources used by the system object. + obj.iio_dev_cfg = {}; + delete(obj.libiio_data_in_dev); + delete(obj.libiio_data_out_dev); + delete(obj.libiio_ctrl_dev); + end + + function ret = stepImpl(obj, varargin) + % Implement the system object's processing flow. + varargout = cell(1, obj.out_ch_no + length(obj.iio_dev_cfg.mon_ch)); + if(obj.sys_obj_initialized == 0) + return; + end + + % Implement the device configuration flow + for i = 1 : length(obj.iio_dev_cfg.cfg_ch) + if(~isempty(varargin{1}{i + obj.in_ch_no})) + if(length(varargin{1}{i + obj.in_ch_no}) == 1) + new_data = (varargin{1}{i + obj.in_ch_no} ~= obj.num_cfg_in(i)); + else + new_data = ~strncmp(char(varargin{1}{i + obj.in_ch_no}'), char(obj.str_cfg_in(i,:)), length(varargin{1}{i + obj.in_ch_no})); + end + if(new_data == 1) + if(length(varargin{1}{i + obj.in_ch_no}) == 1) + obj.num_cfg_in(i) = varargin{1}{i + obj.in_ch_no}; + str = num2str(obj.num_cfg_in(i)); + else + for j = 1:length(varargin{1}{i + obj.in_ch_no}) + obj.str_cfg_in(i,j) = varargin{1}{i + obj.in_ch_no}(j); + end + obj.str_cfg_in(i,j+1) = 0; + str = char(obj.str_cfg_in(i,:)); + end + writeAttributeString(obj.iio_dev_cfg.cfg_ch(i).ctrl_dev, obj.iio_dev_cfg.cfg_ch(i).port_attr, str); + end + end + end + + % Implement the data transmit flow + writeData(obj.libiio_data_in_dev, varargin{1}); + + % Implement the data capture flow + [~, data] = readData(obj.libiio_data_out_dev); + for i = 1 : obj.out_ch_no + varargout{i} = data{i}; + end + + % Implement the parameters monitoring flow + for i = 1 : length(obj.iio_dev_cfg.mon_ch) + [~, val] = readAttributeDouble(obj.iio_dev_cfg.mon_ch(i).ctrl_dev, obj.iio_dev_cfg.mon_ch(i).port_attr); + varargout{obj.out_ch_no + i} = val; + end + + ret=varargout; + end + + function ret = writeFirData(obj, fir_data_file) + fir_data_str = fileread(fir_data_file); + ret = writeAttributeString(obj.libiio_ctrl_dev, 'in_out_voltage_filter_fir_en', '0'); + if ret<0 + return; + end + ret = writeAttributeString(obj.libiio_ctrl_dev, 'filter_fir_config', fir_data_str); + if ret<0 + return; + end + ret = writeAttributeString(obj.libiio_ctrl_dev, 'in_out_voltage_filter_fir_en', '1'); + if ret<0 + return; + end + end + end +end diff --git a/bindings/matlab/libiio_if.m b/bindings/matlab/libiio_if.m new file mode 100644 index 0000000..9fde04d --- /dev/null +++ b/bindings/matlab/libiio_if.m @@ -0,0 +1,701 @@ +% Copyright 2014(c) Analog Devices, Inc. +% +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without modification, +% are permitted provided that the following conditions are met: +% - Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% - Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in +% the documentation and/or other materials provided with the +% distribution. +% - Neither the name of Analog Devices, Inc. nor the names of its +% contributors may be used to endorse or promote products derived +% from this software without specific prior written permission. +% - The use of this software may or may not infringe the patent rights +% of one or more patent holders. This license does not release you +% from the requirement that you obtain separate licenses from these +% patent holders to use this software. +% - Use of the software either in source or binary form or filter designs +% resulting from the use of this software, must be connected to, run +% on or loaded to an Analog Devices Inc. component. +% +% THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +% INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +% PARTICULAR PURPOSE ARE DISCLAIMED. +% +% IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY +% RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +% THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +classdef libiio_if < handle + % libiio_if Interface object for for IIO devices + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Protected properties + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + properties (Access = protected) + libname = 'libiio'; + hname = 'iio-wrapper.h'; + dev_name = ''; + data_ch_no = 0; + data_ch_size = 0; + dev_type = ''; + iio_ctx = {}; + iio_dev = {}; + iio_buffer = {}; + iio_channel = {}; + iio_buf_size = 8192; + iio_scan_elm_no = 0; + if_initialized = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Static private methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods (Static, Access = private) + function out = modInstanceCnt(val) + % Manages the number of object instances to handle proper DLL unloading + persistent instance_cnt; + if isempty(instance_cnt) + instance_cnt = 0; + end + instance_cnt = instance_cnt + val; + out = instance_cnt; + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Protected methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods (Access = protected) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Creates the network context + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = createNetworkContext(obj, ip_address) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Create the network context + obj.iio_ctx = calllib(obj.libname, 'iio_create_network_context', ip_address); + + % Check if the network context is valid + if (isNull(obj.iio_ctx)) + obj.iio_ctx = {}; + err_msg = 'Could not connect to the IIO server!'; + return; + end + + % Increase the object's instance count + libiio_if.modInstanceCnt(1); + msg_log = [msg_log sprintf('%s: Connected to IP %s\n', class(obj), ip_address)]; + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Releases the network context and unload the libiio library + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function releaseContext(obj) + calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx); + obj.iio_ctx = {}; + instCnt = libiio_if.modInstanceCnt(-1); + if(instCnt == 0) + unloadlibrary(obj.libname); + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Checks the compatibility of the different software modules. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = checkVersions(obj) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Create a set of pointers to read the iiod and dll versions + data = zeros(1, 10); + remote_pMajor = libpointer('uint32Ptr', data(1)); + remote_pMinor = libpointer('uint32Ptr', data(2)); + remote_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]); + local_pMajor = libpointer('uint32Ptr', data(1)); + local_pMinor = libpointer('uint32Ptr', data(2)); + local_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]); + + % get remote libiio version + calllib(obj.libname, 'iio_context_get_version', obj.iio_ctx, remote_pMajor, remote_pMinor, remote_pGitTag); + % extract git hash without trailing null char + remote_githash = remote_pGitTag.Value(1:7); + remote_version_str = sprintf('Remote libiio version: %d.%d, (git-%s)', remote_pMajor.Value, remote_pMinor.Value, remote_githash); + msg_log = [msg_log sprintf('%s: %s\n', class(obj), remote_version_str)]; + + % get local libiio version + calllib(obj.libname, 'iio_library_get_version', local_pMajor, local_pMinor, local_pGitTag); + local_githash = local_pGitTag.Value(1:7); + local_version_str = sprintf('Local libiio version: %d.%d, (git-%s)', local_pMajor.Value, local_pMinor.Value, local_githash); + msg_log = [msg_log sprintf('%s: %s\n', class(obj), local_version_str)]; + + if(remote_pMajor.Value < local_pMajor.Value) + err_msg = ['The libiio version running on the device is outdated! ' ... + 'Run the adi_update_tools.sh script to get libiio up to date.']; + return; + elseif(remote_pMajor.Value > local_pMajor.Value) + err_msg = ['The libiio version on the local host is outdated! ' ... + 'On Windows, reinstall the dll using the latest installer ' ... + 'from the Analog Devices wiki.']; + return; + end + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Detect if the specified device is present in the system + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = initDevice(obj, dev_name) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Store the device name + obj.dev_name = dev_name; + + % Get the number of devices + nb_devices = calllib(obj.libname, 'iio_context_get_devices_count', obj.iio_ctx); + + % If no devices are present return with error + if(nb_devices == 0) + err_msg = 'No devices were detected in the system!'; + return; + end + msg_log = [msg_log sprintf('%s: Found %d devices in the system\n', class(obj), nb_devices)]; + + % Detect if the targeted device is installed + dev_found = 0; + for i = 0 : nb_devices - 1 + dev = calllib(obj.libname, 'iio_context_get_device', obj.iio_ctx, i); + name = calllib(obj.libname, 'iio_device_get_name', dev); + if(strcmp(name, dev_name)) + obj.iio_dev = dev; + dev_found = 1; + break; + end + clear dev; + end + + % Check if the target device was detected + if(dev_found == 0) + err_msg = 'Could not find target configuration device!'; + return; + end + + msg_log = [msg_log sprintf('%s: %s was found in the system\n', class(obj), obj.dev_name)]; + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Initializes the output data channels + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = initOutputDataChannels(obj, ch_no, ch_size) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Save the number of channels and size + obj.data_ch_no = ch_no; + obj.data_ch_size = ch_size; + + % Get the number of channels that the device has + nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev); + if(nb_channels == 0) + err_msg = 'The selected device does not have any channels!'; + return; + end + + % Enable the data channels + if(ch_no ~= 0) + % Check if the device has output channels. The + % logic here assumes that a device can have + % only input or only output channels + obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0); + is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1}); + if(is_output == 0) + err_msg = 'The selected device does not have output channels!'; + return; + end + % Enable all the channels + for j = 0 : nb_channels - 1 + obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j); + calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1}); + is_scan_element = calllib(obj.libname, 'iio_channel_is_scan_element', obj.iio_channel{j+1}); + if(is_scan_element == 1) + obj.iio_scan_elm_no = obj.iio_scan_elm_no + 1; + end + end + msg_log = [msg_log sprintf('%s: Found %d output channels for the device %s\n', class(obj), obj.iio_scan_elm_no, obj.dev_name)]; + + % Check if the number of channels in the device + % is greater or equal to the system object + % input channels + if(obj.iio_scan_elm_no < ch_no) + obj.iio_channel = {}; + err_msg = 'The selected device does not have enough output channels!'; + return; + end + + % Enable the DAC buffer output + obj.if_initialized = 1; + ret = writeAttributeString(obj, 'altvoltage0*raw', '0'); + obj.if_initialized = 0; + if(ret < 0) + obj.iio_channel = {}; + err_msg = 'Could not enable the DAC buffer output!'; + return; + end + + % Create the IIO buffer used to write data + obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no; + obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,... + obj.data_ch_size, 1); + end + + msg_log = [msg_log sprintf('%s: %s output data channels successfully initialized\n', class(obj), obj.dev_name)]; + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Initializes the input data channels + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = initInputDataChannels(obj, ch_no, ch_size) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Save the number of channels and size + obj.data_ch_no = ch_no; + obj.data_ch_size = ch_size; + + % Get the number of channels that the device has + nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev); + if(nb_channels == 0) + err_msg = 'The selected device does not have any channels!'; + return; + end + + % Enable the system object output channels + if(ch_no ~= 0) + % Check if the device has input channels. The + % logic here assumes that a device can have + % only input or only output channels + obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0); + is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1}); + if(is_output == 1) + err_msg = 'The selected device does not have input channels!'; + return; + end + msg_log = [msg_log sprintf('%s: Found %d input channels for the device %s\n', class(obj), nb_channels, obj.dev_name)]; + + % Check if the number of channels in the device + % is greater or equal to the system object + % output channels + if(nb_channels < ch_no) + obj.iio_channel = {}; + err_msg = 'The selected device does not have enough input channels!'; + return; + end + + % Enable the channels + for j = 0 : ch_no - 1 + obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j); + calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1}); + end + for j = ch_no : nb_channels - 1 + obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j); + calllib(obj.libname, 'iio_channel_disable', obj.iio_channel{j+1}); + end + % Create the IIO buffer used to read data + obj.iio_buf_size = obj.data_ch_size * obj.data_ch_no; + obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev, obj.iio_buf_size, 0); + end + + msg_log = [msg_log sprintf('%s: %s input data channels successfully initialized\n', class(obj), obj.dev_name)]; + + % Set the return code to success + ret = 0; + end + + end + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Public methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Constructor + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function obj = libiio_if() + % Constructor + obj.if_initialized = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Destructor + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function delete(obj) + % Release any resources used by the system object. + if((obj.if_initialized == 1) && libisloaded(obj.libname)) + if(~isempty(obj.iio_buffer)) + calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer); + end + if(~isempty(obj.iio_ctx)) + calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx); + end + obj.iio_buffer = {}; + obj.iio_channel = {}; + obj.iio_dev = {}; + obj.iio_ctx = {}; + instCnt = libiio_if.modInstanceCnt(-1); + if(instCnt == 0) + unloadlibrary(obj.libname); + end + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Initializes the libiio interface + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = init(obj, ip_address, ... + dev_name, dev_type, ... + data_ch_no, data_ch_size) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Save the device type + obj.dev_type = dev_type; + + % Set the initialization status to fail + obj.if_initialized = 0; + + % Load the libiio library + if(~libisloaded(obj.libname)) + try + % ignore unknown type warnings due to header parsing limitations + warnState = warning('off', 'MATLAB:loadlibrary:TypeNotFound'); + cleanupObj = onCleanup(@()warning(warnState)); + [notfound, warnings] = loadlibrary(obj.libname, obj.hname, 'addheader', 'iio.h'); + cleanupObj = []; % restore the warning state + catch exception + err_msg = exception.message; + return; + end + end + + if(~libisloaded(obj.libname)) + err_msg = 'Could not load the libiio library!'; + return; + end + + % Create the network context + [ret, err_msg, msg_log] = createNetworkContext(obj, ip_address); + if(ret < 0) + return; + end + + % Check the software versions + [ret, err_msg, msg_log_new] = checkVersions(obj); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + + % Initialize the device + [ret, err_msg, msg_log_new] = initDevice(obj, dev_name); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + + % Initialize the output data channels + if(strcmp(dev_type, 'OUT')) + [ret, err_msg, msg_log_new] = initOutputDataChannels(obj, data_ch_no, data_ch_size); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + end + + % Initialize the input data channels + if(strcmp(dev_type, 'IN')) + [ret, err_msg, msg_log_new] = initInputDataChannels(obj, data_ch_no, data_ch_size); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + end + + % Set the initialization status to success + obj.if_initialized = 1; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Implement the data capture flow + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, data] = readData(obj) + % Initialize the return values + ret = -1; + data = cell(1, obj.data_ch_no); + for i = 1 : obj.data_ch_no + data{i} = zeros(obj.data_ch_size, 1); + end + + % Check if the interface is initialized + if(obj.if_initialized == 0) + return; + end + + % Check if the device type is output + if(~strcmp(obj.dev_type, 'IN')) + return; + end + + % Read the data + calllib(obj.libname, 'iio_buffer_refill', obj.iio_buffer); + buffer = calllib(obj.libname, 'iio_buffer_first', obj.iio_buffer, obj.iio_channel{1}); + setdatatype(buffer, 'int16Ptr', obj.iio_buf_size); + for i = 1 : obj.data_ch_no + data{i} = double(buffer.Value(i:obj.data_ch_no:end)); + end + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Implement the data transmit flow + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function ret = writeData(obj, data) + % Initialize the return values + ret = -1; + + % Check if the interface is initialized + if(obj.if_initialized == 0) + return; + end + + % Check if the device type is input + if(~strcmp(obj.dev_type, 'OUT')) + return; + end + + % Destroy the buffer + calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer); + obj.iio_buffer = {}; + + % Enable the DAC buffer output + ret = writeAttributeString(obj, 'altvoltage0*raw', '0'); + if(ret < 0) + obj.iio_channel = {}; + err_msg = 'Could not enable the DAC buffer output!'; + return; + end + + % Create the IIO buffer used to write data + obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no; + obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,... + obj.data_ch_size, 1); + + % Transmit the data + buffer = calllib(obj.libname, 'iio_buffer_start', obj.iio_buffer); + setdatatype(buffer, 'int16Ptr', obj.iio_buf_size); + for i = 1 : obj.data_ch_no + buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = int16(data{i}); + end + for i = obj.data_ch_no + 1 : obj.iio_scan_elm_no + buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = 0; + end + calllib(obj.libname, 'iio_buffer_push', obj.iio_buffer); + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Find an attribute based on the name. The name can contain wildcard '*' characters + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, ch, attr] = findAttribute(obj, attr_name) + % Initialize the return values + ret = -1; + ch = 0; + attr = ''; + + % Check if the interface is initialized + if(obj.if_initialized == 0) + return; + end + + % Check if this is a device attribute + name = calllib(obj.libname, 'iio_device_find_attr', obj.iio_dev, attr_name); + if(~isempty(name)) + ret = 0; + return; + end + + % This is a channel attribute, search for the corresponding channel + chn_no = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev); + for k = 0 : chn_no - 1 + ch = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, k); + attr_no = calllib(obj.libname, 'iio_channel_get_attrs_count', ch); + attr_found = 0; + for l = 0 : attr_no - 1 + attr = calllib(obj.libname, 'iio_channel_get_attr', ch, l); + name = calllib(obj.libname, 'iio_channel_attr_get_filename', ch, attr); + % The attribute to find can contain wildcard '*' characters, + % search for all the substrings in the attribute name + str_find = strsplit(attr_name, '*'); + str_find = str_find(find(~strcmp(str_find, ''))); + has_wildcard = ~isempty(strfind(attr_name, '*')); + attr_found = 1; + for i = 1 : length(str_find) + if(has_wildcard == 0) + ret = strcmp(name, str_find{i}); + if(ret == 0) + ret = []; + end + else + ret = strfind(name, str_find{i}); + end + if(isempty(ret)) + attr_found = 0; + break; + end + end + if(attr_found == 1) + break; + end + clear attr; + end + % Check if the attribute was found + if(attr_found == 0) + clear ch; + else + ret = 1; + break; + end + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Read an attribute as a double value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, val] = readAttributeDouble(obj, attr_name) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + val = 0; + return; + end + + % Create a double pointer to be used for data read + data = zeros(1, 10); + pData = libpointer('doublePtr', data(1)); + + % Read the attribute value + if(ret > 0) + calllib(obj.libname, 'iio_channel_attr_read_double', ch, attr, pData); + clear ch; + clear attr; + else + calllib(obj.libname, 'iio_device_attr_read_double', obj.iio_dev, attr_name, pData); + end + val = pData.Value; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Read an attribute as a string value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, val] = readAttributeString(obj, attr_name) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + val = ''; + return; + end + + % Create a pointer to be used for data read + data = char(ones(1, 512)); + pData = libpointer('stringPtr', data); + + % Read the attribute value + if(ret > 0) + [~, ~, ~, val] = calllib(obj.libname, 'iio_channel_attr_read', ch, attr, pData, 512); + clear ch; + clear attr; + else + [~, ~, ~, val] = calllib(obj.libname, 'iio_device_attr_read', obj.iio_dev, attr_name, pData, 512); + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Write a string double value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function ret = writeAttributeDouble(obj, attr_name, val) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + return; + end + + % Write the attribute + if(ret > 0) + calllib(obj.libname, 'iio_channel_attr_write_double', ch, attr, val); + clear ch; + clear attr; + else + calllib(obj.libname, 'iio_device_attr_write_double', obj.iio_dev, attr_name, val); + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Write a string attribute value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function ret = writeAttributeString(obj, attr_name, str) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + return; + end + + % Write the attribute + if(ret > 0) + calllib(obj.libname, 'iio_channel_attr_write', ch, attr, str); + clear ch; + clear attr; + else + calllib(obj.libname, 'iio_device_attr_write', obj.iio_dev, attr_name, str); + end + end + end +end diff --git a/bindings/matlab/libiio_if_daq2.m b/bindings/matlab/libiio_if_daq2.m new file mode 100644 index 0000000..0ac5708 --- /dev/null +++ b/bindings/matlab/libiio_if_daq2.m @@ -0,0 +1,701 @@ +% Copyright 2014(c) Analog Devices, Inc. +% +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without modification, +% are permitted provided that the following conditions are met: +% - Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% - Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in +% the documentation and/or other materials provided with the +% distribution. +% - Neither the name of Analog Devices, Inc. nor the names of its +% contributors may be used to endorse or promote products derived +% from this software without specific prior written permission. +% - The use of this software may or may not infringe the patent rights +% of one or more patent holders. This license does not release you +% from the requirement that you obtain separate licenses from these +% patent holders to use this software. +% - Use of the software either in source or binary form or filter designs +% resulting from the use of this software, must be connected to, run +% on or loaded to an Analog Devices Inc. component. +% +% THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +% INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +% PARTICULAR PURPOSE ARE DISCLAIMED. +% +% IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY +% RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +% THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +classdef libiio_if < handle + % libiio_if Interface object for for IIO devices + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Protected properties + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + properties (Access = protected) + libname = 'libiio'; + hname = 'iio.h'; + dev_name = ''; + data_ch_no = 0; + data_ch_size = 0; + dev_type = ''; + iio_ctx = {}; + iio_dev = {}; + iio_buffer = {}; + iio_channel = {}; + iio_buf_size = 8192; + iio_scan_elm_no = 0; + if_initialized = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Static private methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods (Static, Access = private) + function out = modInstanceCnt(val) + % Manages the number of object instances to handle proper DLL unloading + persistent instance_cnt; + if isempty(instance_cnt) + instance_cnt = 0; + end + instance_cnt = instance_cnt + val; + out = instance_cnt; + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Protected methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods (Access = protected) + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Creates the network context + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = createNetworkContext(obj, ip_address) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Create the network context + obj.iio_ctx = calllib(obj.libname, 'iio_create_network_context', ip_address); + + % Check if the network context is valid + if (isNull(obj.iio_ctx)) + obj.iio_ctx = {}; + err_msg = 'Could not connect to the IIO server!'; + return; + end + + % Increase the object's instance count + libiio_if.modInstanceCnt(1); + msg_log = [msg_log sprintf('%s: Connected to IP %s\n', class(obj), ip_address)]; + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Releases the network context and unload the libiio library + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function releaseContext(obj) + calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx); + obj.iio_ctx = {}; + instCnt = libiio_if.modInstanceCnt(-1); + if(instCnt == 0) + unloadlibrary(obj.libname); + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Checks the compatibility of the different software modules. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = checkVersions(obj) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Create a set of pointers to read the iiod and dll versions + data = zeros(1, 10); + remote_pMajor = libpointer('uint32Ptr', data(1)); + remote_pMinor = libpointer('uint32Ptr', data(2)); + remote_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]); + local_pMajor = libpointer('uint32Ptr', data(1)); + local_pMinor = libpointer('uint32Ptr', data(2)); + local_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]); + + % get remote libiio version + calllib(obj.libname, 'iio_context_get_version', obj.iio_ctx, remote_pMajor, remote_pMinor, remote_pGitTag); + % extract git hash without trailing null char + remote_githash = remote_pGitTag.Value(1:7); + remote_version_str = sprintf('Remote libiio version: %d.%d, (git-%s)', remote_pMajor.Value, remote_pMinor.Value, remote_githash); + msg_log = [msg_log sprintf('%s: %s\n', class(obj), remote_version_str)]; + + % get local libiio version + calllib(obj.libname, 'iio_library_get_version', local_pMajor, local_pMinor, local_pGitTag); + local_githash = local_pGitTag.Value(1:7); + local_version_str = sprintf('Local libiio version: %d.%d, (git-%s)', local_pMajor.Value, local_pMinor.Value, local_githash); + msg_log = [msg_log sprintf('%s: %s\n', class(obj), local_version_str)]; + + if(remote_pMajor.Value < local_pMajor.Value) + err_msg = ['The libiio version running on the device is outdated! ' ... + 'Run the adi_update_tools.sh script to get libiio up to date.']; + return; + elseif(remote_pMajor.Value > local_pMajor.Value) + err_msg = ['The libiio version on the local host is outdated! ' ... + 'On Windows, reinstall the dll using the latest installer ' ... + 'from the Analog Devices wiki.']; + return; + end + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Detect if the specified device is present in the system + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = initDevice(obj, dev_name) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Store the device name + obj.dev_name = dev_name; + + % Get the number of devices + nb_devices = calllib(obj.libname, 'iio_context_get_devices_count', obj.iio_ctx); + + % If no devices are present return with error + if(nb_devices == 0) + err_msg = 'No devices were detected in the system!'; + return; + end + msg_log = [msg_log sprintf('%s: Found %d devices in the system\n', class(obj), nb_devices)]; + + % Detect if the targeted device is installed + dev_found = 0; + for i = 0 : nb_devices - 1 + dev = calllib(obj.libname, 'iio_context_get_device', obj.iio_ctx, i); + name = calllib(obj.libname, 'iio_device_get_name', dev); + if(strcmp(name, dev_name)) + obj.iio_dev = dev; + dev_found = 1; + break; + end + clear dev; + end + + % Check if the target device was detected + if(dev_found == 0) + err_msg = 'Could not find target configuration device!'; + return; + end + + msg_log = [msg_log sprintf('%s: %s was found in the system\n', class(obj), obj.dev_name)]; + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Initializes the output data channels + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = initOutputDataChannels(obj, ch_no, ch_size) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Save the number of channels and size + obj.data_ch_no = ch_no; + obj.data_ch_size = ch_size; + + % Get the number of channels that the device has + nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev); + if(nb_channels == 0) + err_msg = 'The selected device does not have any channels!'; + return; + end + + % Enable the data channels + if(ch_no ~= 0) + % Check if the device has output channels. The + % logic here assumes that a device can have + % only input or only output channels + obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0); + is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1}); + if(is_output == 0) + err_msg = 'The selected device does not have output channels!'; + return; + end + % Enable all the channels + for j = 0 : nb_channels - 1 + obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j); + if(j < ch_no) + calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1}); + is_scan_element = calllib(obj.libname, 'iio_channel_is_scan_element', obj.iio_channel{j+1}); + if(is_scan_element == 1) + obj.iio_scan_elm_no = obj.iio_scan_elm_no + 1; + end + else + calllib(obj.libname, 'iio_channel_disable', obj.iio_channel{j+1}); + end + end + msg_log = [msg_log sprintf('%s: Found %d output channels for the device %s\n', class(obj), obj.iio_scan_elm_no, obj.dev_name)]; + + % Check if the number of channels in the device + % is greater or equal to the system object + % input channels + if(obj.iio_scan_elm_no < ch_no) + obj.iio_channel = {}; + err_msg = 'The selected device does not have enough output channels!'; + return; + end + + % Enable the DAC buffer output + obj.if_initialized = 1; + ret = writeAttributeString(obj, 'altvoltage0*raw', '0'); + obj.if_initialized = 0; + if(ret < 0) + obj.iio_channel = {}; + err_msg = 'Could not enable the DAC buffer output!'; + return; + end + + % Create the IIO buffer used to write data + obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no; + obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,... + obj.data_ch_size, 1); + end + + msg_log = [msg_log sprintf('%s: %s output data channels successfully initialized\n', class(obj), obj.dev_name)]; + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Initializes the input data channels + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = initInputDataChannels(obj, ch_no, ch_size) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Save the number of channels and size + obj.data_ch_no = ch_no; + obj.data_ch_size = ch_size; + + % Get the number of channels that the device has + nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev); + if(nb_channels == 0) + err_msg = 'The selected device does not have any channels!'; + return; + end + + % Enable the system object output channels + if(ch_no ~= 0) + % Check if the device has input channels. The + % logic here assumes that a device can have + % only input or only output channels + obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0); + is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1}); + if(is_output == 1) + err_msg = 'The selected device does not have input channels!'; + return; + end + msg_log = [msg_log sprintf('%s: Found %d input channels for the device %s\n', class(obj), nb_channels, obj.dev_name)]; + + % Check if the number of channels in the device + % is greater or equal to the system object + % output channels + if(nb_channels < ch_no) + obj.iio_channel = {}; + err_msg = 'The selected device does not have enough input channels!'; + return; + end + + % Enable the channels + for j = 0 : ch_no - 1 + obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j); + calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1}); + end + for j = ch_no : nb_channels - 1 + obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j); + calllib(obj.libname, 'iio_channel_disable', obj.iio_channel{j+1}); + end + % Create the IIO buffer used to read data + obj.iio_buf_size = obj.data_ch_size * obj.data_ch_no; + obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev, obj.iio_buf_size, 0); + end + + msg_log = [msg_log sprintf('%s: %s input data channels successfully initialized\n', class(obj), obj.dev_name)]; + + % Set the return code to success + ret = 0; + end + + end + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Public methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Constructor + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function obj = libiio_if() + % Constructor + obj.if_initialized = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Destructor + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function delete(obj) + % Release any resources used by the system object. + if((obj.if_initialized == 1) && libisloaded(obj.libname)) + if(~isempty(obj.iio_buffer)) + calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer); + end + if(~isempty(obj.iio_ctx)) + calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx); + end + obj.iio_buffer = {}; + obj.iio_channel = {}; + obj.iio_dev = {}; + obj.iio_ctx = {}; + instCnt = libiio_if.modInstanceCnt(-1); + if(instCnt == 0) + unloadlibrary(obj.libname); + end + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Initializes the libiio interface + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, err_msg, msg_log] = init(obj, ip_address, ... + dev_name, dev_type, ... + data_ch_no, data_ch_size) + % Initialize the return values + ret = -1; + err_msg = ''; + msg_log = []; + + % Save the device type + obj.dev_type = dev_type; + + % Set the initialization status to fail + obj.if_initialized = 0; + + % Load the libiio library + if(~libisloaded(obj.libname)) + try + [notfound, warnings] = loadlibrary(obj.libname, obj.hname); + catch exception + err_msg = exception.message; + return; + end + end + + if(~libisloaded(obj.libname)) + err_msg = 'Could not load the libiio library!'; + return; + end + + % Create the network context + [ret, err_msg, msg_log] = createNetworkContext(obj, ip_address); + if(ret < 0) + return; + end + + % Check the software versions + [ret, err_msg, msg_log_new] = checkVersions(obj); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + + % Initialize the device + [ret, err_msg, msg_log_new] = initDevice(obj, dev_name); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + + % Initialize the output data channels + if(strcmp(dev_type, 'OUT')) + [ret, err_msg, msg_log_new] = initOutputDataChannels(obj, data_ch_no, data_ch_size); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + end + + % Initialize the input data channels + if(strcmp(dev_type, 'IN')) + [ret, err_msg, msg_log_new] = initInputDataChannels(obj, data_ch_no, data_ch_size); + msg_log = [msg_log msg_log_new]; + if(ret < 0) + releaseContext(obj); + return; + end + end + + % Set the initialization status to success + obj.if_initialized = 1; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Implement the data capture flow + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, data] = readData(obj) + % Initialize the return values + ret = -1; + data = cell(1, obj.data_ch_no); + for i = 1 : obj.data_ch_no + data{i} = zeros(obj.data_ch_size, 1); + end + + % Check if the interface is initialized + if(obj.if_initialized == 0) + return; + end + + % Check if the device type is output + if(~strcmp(obj.dev_type, 'IN')) + return; + end + + % Read the data + calllib(obj.libname, 'iio_buffer_refill', obj.iio_buffer); + buffer = calllib(obj.libname, 'iio_buffer_first', obj.iio_buffer, obj.iio_channel{1}); + setdatatype(buffer, 'int16Ptr', obj.iio_buf_size); + for i = 1 : obj.data_ch_no + data{i} = double(buffer.Value(i:obj.data_ch_no:end)); + end + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Implement the data transmit flow + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function ret = writeData(obj, data) + % Initialize the return values + ret = -1; + + % Check if the interface is initialized + if(obj.if_initialized == 0) + return; + end + + % Check if the device type is input + if(~strcmp(obj.dev_type, 'OUT')) + return; + end + + % Destroy the buffer + calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer); + obj.iio_buffer = {}; + + % Enable the DAC buffer output + ret = writeAttributeString(obj, 'altvoltage0*raw', '0'); + if(ret < 0) + obj.iio_channel = {}; + err_msg = 'Could not enable the DAC buffer output!'; + return; + end + + % Create the IIO buffer used to write data + obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no; + obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,... + obj.data_ch_size, 1); + + % Transmit the data + buffer = calllib(obj.libname, 'iio_buffer_start', obj.iio_buffer); + setdatatype(buffer, 'int16Ptr', obj.iio_buf_size); + for i = 1 : obj.data_ch_no + buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = int16(data{i}); + end + for i = obj.data_ch_no + 1 : obj.iio_scan_elm_no + buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = 0; + end + calllib(obj.libname, 'iio_buffer_push', obj.iio_buffer); + + % Set the return code to success + ret = 0; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Find an attribute based on the name. The name can contain wildcard '*' characters + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, ch, attr] = findAttribute(obj, attr_name) + % Initialize the return values + ret = -1; + ch = 0; + attr = ''; + + % Check if the interface is initialized + if(obj.if_initialized == 0) + return; + end + + % Check if this is a device attribute + name = calllib(obj.libname, 'iio_device_find_attr', obj.iio_dev, attr_name); + if(~isempty(name)) + ret = 0; + return; + end + + % This is a channel attribute, search for the corresponding channel + chn_no = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev); + for k = 0 : chn_no - 1 + ch = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, k); + attr_no = calllib(obj.libname, 'iio_channel_get_attrs_count', ch); + attr_found = 0; + for l = 0 : attr_no - 1 + attr = calllib(obj.libname, 'iio_channel_get_attr', ch, l); + name = calllib(obj.libname, 'iio_channel_attr_get_filename', ch, attr); + % The attribute to find can contain wildcard '*' characters, + % search for all the substrings in the attribute name + str_find = strsplit(attr_name, '*'); + str_find = str_find(find(~strcmp(str_find, ''))); + has_wildcard = ~isempty(strfind(attr_name, '*')); + attr_found = 1; + for i = 1 : length(str_find) + if(has_wildcard == 0) + ret = strcmp(name, str_find{i}); + if(ret == 0) + ret = []; + end + else + ret = strfind(name, str_find{i}); + end + if(isempty(ret)) + attr_found = 0; + break; + end + end + if(attr_found == 1) + break; + end + clear attr; + end + % Check if the attribute was found + if(attr_found == 0) + clear ch; + else + ret = 1; + break; + end + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Read an attribute as a double value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, val] = readAttributeDouble(obj, attr_name) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + val = 0; + return; + end + + % Create a double pointer to be used for data read + data = zeros(1, 10); + pData = libpointer('doublePtr', data(1)); + + % Read the attribute value + if(ret > 0) + calllib(obj.libname, 'iio_channel_attr_read_double', ch, attr, pData); + clear ch; + clear attr; + else + calllib(obj.libname, 'iio_device_attr_read_double', obj.iio_dev, attr_name, pData); + end + val = pData.Value; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Read an attribute as a string value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function [ret, val] = readAttributeString(obj, attr_name) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + val = ''; + return; + end + + % Create a pointer to be used for data read + data = char(ones(1, 512)); + pData = libpointer('stringPtr', data); + + % Read the attribute value + if(ret > 0) + [~, ~, ~, val] = calllib(obj.libname, 'iio_channel_attr_read', ch, attr, pData, 512); + clear ch; + clear attr; + else + [~, ~, ~, val] = calllib(obj.libname, 'iio_device_attr_read', obj.iio_dev, attr_name, pData, 512); + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Write a string double value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function ret = writeAttributeDouble(obj, attr_name, val) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + return; + end + + % Write the attribute + if(ret > 0) + calllib(obj.libname, 'iio_channel_attr_write_double', ch, attr, val); + clear ch; + clear attr; + else + calllib(obj.libname, 'iio_device_attr_write_double', obj.iio_dev, attr_name, val); + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Write a string attribute value + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function ret = writeAttributeString(obj, attr_name, str) + % Find the attribute + [ret, ch, attr] = findAttribute(obj, attr_name); + if(ret < 0) + return; + end + + % Write the attribute + if(ret > 0) + calllib(obj.libname, 'iio_channel_attr_write', ch, attr, str); + clear ch; + clear attr; + else + calllib(obj.libname, 'iio_device_attr_write', obj.iio_dev, attr_name, str); + end + end + end +end diff --git a/bindings/python/.gitignore b/bindings/python/.gitignore new file mode 100644 index 0000000..cbf6e08 --- /dev/null +++ b/bindings/python/.gitignore @@ -0,0 +1,3 @@ +setup.py +*.pyc +__pycache__/ diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt new file mode 100644 index 0000000..4ba6aca --- /dev/null +++ b/bindings/python/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8.7) +project(libiio-py NONE) + +include(FindPythonInterp) + +if (PYTHONINTERP_FOUND) + option(PYTHON_BINDINGS "Install Python bindings" ON) + + if (PYTHON_BINDINGS) + set(SETUP_PY_IN ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.cmakein) + set(SETUP_PY ${CMAKE_CURRENT_BINARY_DIR}/setup.py) + + configure_file(${SETUP_PY_IN} ${SETUP_PY}) + + add_custom_target(libiio-py ALL DEPENDS ${SETUP_PY} COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} --quiet build) + + if(NOT SKIP_INSTALL_ALL) + install(CODE "execute_process(WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} install --root=\$ENV{DESTDIR}/ --prefix=${CMAKE_INSTALL_PREFIX})") + endif() + endif() +endif() diff --git a/bindings/python/examples/iio_info.py b/bindings/python/examples/iio_info.py new file mode 100755 index 0000000..e29b297 --- /dev/null +++ b/bindings/python/examples/iio_info.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# +# Copyright (C) 2015 Analog Devices, Inc. +# Author: Paul Cercueil <paul.cercueil@analog.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +import iio +from sys import argv + +def main(): + print('Library version: %u.%u (git tag: %s)' % iio.version) + + if len(argv) == 3 and argv[1] == '--uri': + uri = argv[2] + else: + contexts = iio.scan_contexts() + if len(contexts) > 1: + print('Multiple contexts found. Please select one using --uri:') + for index, each in enumerate(contexts): + print('\t%d: %s [%s]' % (index, contexts[each], each)) + return + + uri = next(iter(contexts), None) + + ctx = iio.Context(uri) + + if uri is not None: + print('Using auto-detected IIO context at URI \"%s\"' % uri) + + print('IIO context created: ' + ctx.name) + print('Backend version: %u.%u (git tag: %s)' % ctx.version) + print('Backend description string: ' + ctx.description) + + if len(ctx.attrs) > 0: + print('IIO context has %u attributes:' % len(ctx.attrs)) + for attr, value in ctx.attrs.items(): + print('\t' + attr + ': ' + value) + + print('IIO context has %u devices:' % len(ctx.devices)) + + for dev in ctx.devices: + print('\t' + dev.id + ': ' + dev.name) + + if dev is iio.Trigger: + print('Found trigger! Rate: %u Hz' % dev.frequency) + + print('\t\t%u channels found:' % len(dev.channels)) + + for chn in dev.channels: + print('\t\t\t%s: %s (%s)' % (chn.id, chn.name or "", 'output' if chn.output else 'input')) + + if len(chn.attrs) != 0: + print('\t\t\t%u channel-specific attributes found:' % len(chn.attrs)) + + for attr in chn.attrs: + try: + print('\t\t\t\t' + attr + ', value: ' + chn.attrs[attr].value) + except OSError as e: + print('Unable to read ' + attr + ': ' + e.strerror) + + if len(dev.attrs) != 0: + print('\t\t%u device-specific attributes found:' % len(dev.attrs)) + + for attr in dev.attrs: + try: + print('\t\t\t' + attr + ', value: ' + dev.attrs[attr].value) + except OSError as e: + print('Unable to read ' + attr + ': ' + e.strerror) + + if len(dev.debug_attrs) != 0: + print('\t\t%u debug attributes found:' % len(dev.debug_attrs)) + + for attr in dev.debug_attrs: + try: + print('\t\t\t' + attr + ', value: ' + dev.debug_attrs[attr].value) + except OSError as e: + print('Unable to read ' + attr + ': ' + e.strerror) + +if __name__ == '__main__': + main() diff --git a/bindings/python/iio.py b/bindings/python/iio.py new file mode 100644 index 0000000..3ffe2a2 --- /dev/null +++ b/bindings/python/iio.py @@ -0,0 +1,864 @@ +#!/usr/bin/env python +# +# Copyright (C) 2014 Analog Devices, Inc. +# Author: Paul Cercueil <paul.cercueil@analog.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +from ctypes import Structure, c_char_p, c_uint, c_int, c_size_t, \ + c_ssize_t, c_char, c_void_p, c_bool, create_string_buffer, \ + POINTER as _POINTER, CDLL as _cdll, memmove as _memmove, byref as _byref +from os import strerror as _strerror +from platform import system as _system +import weakref + +if 'Windows' in _system(): + from ctypes import get_last_error +else: + from ctypes import get_errno + +def _checkNull(result, func, arguments): + if result: + return result + else: + err = get_last_error() if 'Windows' in _system() else get_errno() + raise OSError(err, _strerror(err)) + +def _checkNegative(result, func, arguments): + if result >= 0: + return result + else: + raise OSError(-result, _strerror(-result)) + +class _ScanContext(Structure): + pass +class _ContextInfo(Structure): + pass +class _Context(Structure): + pass +class _Device(Structure): + pass +class _Channel(Structure): + pass +class _Buffer(Structure): + pass + +_ScanContextPtr = _POINTER(_ScanContext) +_ContextInfoPtr = _POINTER(_ContextInfo) +_ContextPtr = _POINTER(_Context) +_DevicePtr = _POINTER(_Device) +_ChannelPtr = _POINTER(_Channel) +_BufferPtr = _POINTER(_Buffer) + +_lib = _cdll('libiio.dll' if 'Windows' in _system() else 'libiio.so.0', + use_errno = True, use_last_error = True) + +_get_backends_count = _lib.iio_get_backends_count +_get_backends_count.restype = c_uint + +_get_backend = _lib.iio_get_backend +_get_backend.argtypes = (c_uint, ) +_get_backend.restype = c_char_p +_get_backend.errcheck = _checkNull + +_create_scan_context = _lib.iio_create_scan_context +_create_scan_context.argtypes = (c_char_p, c_uint) +_create_scan_context.restype = _ScanContextPtr +_create_scan_context.errcheck = _checkNull + +_destroy_scan_context = _lib.iio_scan_context_destroy +_destroy_scan_context.argtypes = (_ScanContextPtr, ) + +_get_context_info_list = _lib.iio_scan_context_get_info_list +_get_context_info_list.argtypes = (_ScanContextPtr, _POINTER(_POINTER(_ContextInfoPtr))) +_get_context_info_list.restype = c_ssize_t +_get_context_info_list.errcheck = _checkNegative + +_context_info_list_free = _lib.iio_context_info_list_free +_context_info_list_free.argtypes = (_POINTER(_ContextInfoPtr), ) + +_context_info_get_description = _lib.iio_context_info_get_description +_context_info_get_description.argtypes = (_ContextInfoPtr, ) +_context_info_get_description.restype = c_char_p + +_context_info_get_uri = _lib.iio_context_info_get_uri +_context_info_get_uri.argtypes = (_ContextInfoPtr, ) +_context_info_get_uri.restype = c_char_p + +_new_local = _lib.iio_create_local_context +_new_local.restype = _ContextPtr +_new_local.errcheck = _checkNull + +_new_xml = _lib.iio_create_xml_context +_new_xml.restype = _ContextPtr +_new_xml.argtypes = (c_char_p, ) +_new_xml.errcheck = _checkNull + +_new_network = _lib.iio_create_network_context +_new_network.restype = _ContextPtr +_new_network.argtypes = (c_char_p, ) +_new_network.errcheck = _checkNull + +_new_default = _lib.iio_create_default_context +_new_default.restype = _ContextPtr +_new_default.errcheck = _checkNull + +_new_uri = _lib.iio_create_context_from_uri +_new_uri.restype = _ContextPtr +_new_uri.errcheck = _checkNull + +_destroy = _lib.iio_context_destroy +_destroy.argtypes = (_ContextPtr, ) + +_get_name = _lib.iio_context_get_name +_get_name.restype = c_char_p +_get_name.argtypes = (_ContextPtr, ) +_get_name.errcheck = _checkNull + +_get_description = _lib.iio_context_get_description +_get_description.restype = c_char_p +_get_description.argtypes = (_ContextPtr, ) + +_get_xml = _lib.iio_context_get_xml +_get_xml.restype = c_char_p +_get_xml.argtypes = (_ContextPtr, ) + +_get_library_version = _lib.iio_library_get_version +_get_library_version.argtypes = (_POINTER(c_uint), _POINTER(c_uint), c_char_p, ) + +_get_version = _lib.iio_context_get_version +_get_version.restype = c_int +_get_version.argtypes = (_ContextPtr, _POINTER(c_uint), _POINTER(c_uint), c_char_p, ) +_get_version.errcheck = _checkNegative + +_get_attrs_count = _lib.iio_context_get_attrs_count +_get_attrs_count.restype = c_uint +_get_attrs_count.argtypes = (_ContextPtr, ) + +_get_attr = _lib.iio_context_get_attr +_get_attr.restype = c_int +_get_attr.argtypes = (_ContextPtr, c_uint, _POINTER(c_char_p), _POINTER(c_char_p)) +_get_attr.errcheck = _checkNegative + +_devices_count = _lib.iio_context_get_devices_count +_devices_count.restype = c_uint +_devices_count.argtypes = (_ContextPtr, ) + +_get_device = _lib.iio_context_get_device +_get_device.restype = _DevicePtr +_get_device.argtypes = (_ContextPtr, c_uint) +_get_device.errcheck = _checkNull + +_set_timeout = _lib.iio_context_set_timeout +_set_timeout.restype = c_int +_set_timeout.argtypes = (_ContextPtr, c_uint, ) +_set_timeout.errcheck = _checkNegative + +_clone = _lib.iio_context_clone +_clone.restype = _ContextPtr +_clone.argtypes = (_ContextPtr, ) +_clone.errcheck = _checkNull + +_d_get_id = _lib.iio_device_get_id +_d_get_id.restype = c_char_p +_d_get_id.argtypes = (_DevicePtr, ) +_d_get_id.errcheck = _checkNull + +_d_get_name = _lib.iio_device_get_name +_d_get_name.restype = c_char_p +_d_get_name.argtypes = (_DevicePtr, ) + +_d_attr_count = _lib.iio_device_get_attrs_count +_d_attr_count.restype = c_uint +_d_attr_count.argtypes = (_DevicePtr, ) + +_d_get_attr = _lib.iio_device_get_attr +_d_get_attr.restype = c_char_p +_d_get_attr.argtypes = (_DevicePtr, ) +_d_get_attr.errcheck = _checkNull + +_d_read_attr = _lib.iio_device_attr_read +_d_read_attr.restype = c_ssize_t +_d_read_attr.argtypes = (_DevicePtr, c_char_p, c_char_p, c_size_t) +_d_read_attr.errcheck = _checkNegative + +_d_write_attr = _lib.iio_device_attr_write +_d_write_attr.restype = c_ssize_t +_d_write_attr.argtypes = (_DevicePtr, c_char_p, c_char_p) +_d_write_attr.errcheck = _checkNegative + +_d_debug_attr_count = _lib.iio_device_get_debug_attrs_count +_d_debug_attr_count.restype = c_uint +_d_debug_attr_count.argtypes = (_DevicePtr, ) + +_d_get_debug_attr = _lib.iio_device_get_debug_attr +_d_get_debug_attr.restype = c_char_p +_d_get_debug_attr.argtypes = (_DevicePtr, ) +_d_get_debug_attr.errcheck = _checkNull + +_d_read_debug_attr = _lib.iio_device_debug_attr_read +_d_read_debug_attr.restype = c_ssize_t +_d_read_debug_attr.argtypes = (_DevicePtr, c_char_p, c_char_p, c_size_t) +_d_read_debug_attr.errcheck = _checkNegative + +_d_write_debug_attr = _lib.iio_device_debug_attr_write +_d_write_debug_attr.restype = c_ssize_t +_d_write_debug_attr.argtypes = (_DevicePtr, c_char_p, c_char_p) +_d_write_debug_attr.errcheck = _checkNegative + +_d_reg_write = _lib.iio_device_reg_write +_d_reg_write.restype = c_int +_d_reg_write.argtypes = (_DevicePtr, c_uint, c_uint) +_d_reg_write.errcheck = _checkNegative + +_d_reg_read = _lib.iio_device_reg_read +_d_reg_read.restype = c_int +_d_reg_read.argtypes = (_DevicePtr, c_uint, _POINTER(c_uint)) +_d_reg_read.errcheck = _checkNegative + +_channels_count = _lib.iio_device_get_channels_count +_channels_count.restype = c_uint +_channels_count.argtypes = (_DevicePtr, ) + +_get_channel = _lib.iio_device_get_channel +_get_channel.restype = _ChannelPtr +_get_channel.argtypes = (_DevicePtr, c_uint) +_get_channel.errcheck = _checkNull + +_get_sample_size = _lib.iio_device_get_sample_size +_get_sample_size.restype = c_int +_get_sample_size.argtypes = (_DevicePtr, ) +_get_sample_size.errcheck = _checkNegative + +_d_is_trigger = _lib.iio_device_is_trigger +_d_is_trigger.restype = c_bool +_d_is_trigger.argtypes = (_DevicePtr, ) + +_d_get_trigger = _lib.iio_device_get_trigger +_d_get_trigger.restype = c_int +_d_get_trigger.argtypes = (_DevicePtr, _DevicePtr, ) +_d_get_trigger.errcheck = _checkNegative + +_d_set_trigger = _lib.iio_device_set_trigger +_d_set_trigger.restype = c_int +_d_set_trigger.argtypes = (_DevicePtr, _DevicePtr, ) +_d_set_trigger.errcheck = _checkNegative + +_d_set_buffers_count = _lib.iio_device_set_kernel_buffers_count +_d_set_buffers_count.restype = c_int +_d_set_buffers_count.argtypes = (_DevicePtr, c_uint) +_d_set_buffers_count.errcheck = _checkNegative + +_c_get_id = _lib.iio_channel_get_id +_c_get_id.restype = c_char_p +_c_get_id.argtypes = (_ChannelPtr, ) +_c_get_id.errcheck = _checkNull + +_c_get_name = _lib.iio_channel_get_name +_c_get_name.restype = c_char_p +_c_get_name.argtypes = (_ChannelPtr, ) + +_c_is_output = _lib.iio_channel_is_output +_c_is_output.restype = c_bool +_c_is_output.argtypes = (_ChannelPtr, ) + +_c_is_scan_element = _lib.iio_channel_is_scan_element +_c_is_scan_element.restype = c_bool +_c_is_scan_element.argtypes = (_ChannelPtr, ) + +_c_attr_count = _lib.iio_channel_get_attrs_count +_c_attr_count.restype = c_uint +_c_attr_count.argtypes = (_ChannelPtr, ) + +_c_get_attr = _lib.iio_channel_get_attr +_c_get_attr.restype = c_char_p +_c_get_attr.argtypes = (_ChannelPtr, ) +_c_get_attr.errcheck = _checkNull + +_c_get_filename = _lib.iio_channel_attr_get_filename +_c_get_filename.restype = c_char_p +_c_get_filename.argtypes = (_ChannelPtr, c_char_p, ) +_c_get_filename.errcheck = _checkNull + +_c_read_attr = _lib.iio_channel_attr_read +_c_read_attr.restype = c_ssize_t +_c_read_attr.argtypes = (_ChannelPtr, c_char_p, c_char_p, c_size_t) +_c_read_attr.errcheck = _checkNegative + +_c_write_attr = _lib.iio_channel_attr_write +_c_write_attr.restype = c_ssize_t +_c_write_attr.argtypes = (_ChannelPtr, c_char_p, c_char_p) +_c_write_attr.errcheck = _checkNegative + +_c_enable = _lib.iio_channel_enable +_c_enable.argtypes = (_ChannelPtr, ) + +_c_disable = _lib.iio_channel_disable +_c_disable.argtypes = (_ChannelPtr, ) + +_c_is_enabled = _lib.iio_channel_is_enabled +_c_is_enabled.restype = c_bool +_c_is_enabled.argtypes = (_ChannelPtr, ) + +_c_read = _lib.iio_channel_read +_c_read.restype = c_ssize_t +_c_read.argtypes = (_ChannelPtr, _BufferPtr, c_void_p, c_size_t, ) + +_c_read_raw = _lib.iio_channel_read_raw +_c_read_raw.restype = c_ssize_t +_c_read_raw.argtypes = (_ChannelPtr, _BufferPtr, c_void_p, c_size_t, ) + +_c_write = _lib.iio_channel_write +_c_write.restype = c_ssize_t +_c_write.argtypes = (_ChannelPtr, _BufferPtr, c_void_p, c_size_t, ) + +_c_write_raw = _lib.iio_channel_write_raw +_c_write_raw.restype = c_ssize_t +_c_write_raw.argtypes = (_ChannelPtr, _BufferPtr, c_void_p, c_size_t, ) + +_create_buffer = _lib.iio_device_create_buffer +_create_buffer.restype = _BufferPtr +_create_buffer.argtypes = (_DevicePtr, c_size_t, c_bool, ) +_create_buffer.errcheck = _checkNull + +_buffer_destroy = _lib.iio_buffer_destroy +_buffer_destroy.argtypes = (_BufferPtr, ) + +_buffer_refill = _lib.iio_buffer_refill +_buffer_refill.restype = c_ssize_t +_buffer_refill.argtypes = (_BufferPtr, ) +_buffer_refill.errcheck = _checkNegative + +_buffer_push_partial = _lib.iio_buffer_push_partial +_buffer_push_partial.restype = c_ssize_t +_buffer_push_partial.argtypes = (_BufferPtr, c_uint, ) +_buffer_push_partial.errcheck = _checkNegative + +_buffer_start = _lib.iio_buffer_start +_buffer_start.restype = c_void_p +_buffer_start.argtypes = (_BufferPtr, ) + +_buffer_end = _lib.iio_buffer_end +_buffer_end.restype = c_void_p +_buffer_end.argtypes = (_BufferPtr, ) + +def _get_lib_version(): + major = c_uint() + minor = c_uint() + buf = create_string_buffer(8) + _get_library_version(_byref(major), _byref(minor), buf) + return (major.value, minor.value, buf.value.decode('ascii') ) + +version = _get_lib_version() +backends = [ _get_backend(x).decode('ascii') for x in range(0, _get_backends_count()) ] + +class _Attr(object): + def __init__(self, name, filename = None): + self._name = name + self._name_ascii = name.encode('ascii') + self._filename = name if filename is None else filename + + def __str__(self): + return self._name + + name = property(lambda self: self._name, None, None, + "The name of this attribute.\n\ttype=str") + filename = property(lambda self: self._filename, None, None, + "The filename in sysfs to which this attribute is bound.\n\ttype=str") + value = property(lambda self: self.__read(), lambda self, x: self.__write(x), + None, "Current value of this attribute.\n\ttype=str") + +class ChannelAttr(_Attr): + """Represents an attribute of a channel.""" + + def __init__(self, channel, name): + super(ChannelAttr, self).__init__(name, _c_get_filename(channel, name.encode('ascii')).decode('ascii')) + self._channel = channel + + def _Attr__read(self): + buf = create_string_buffer(1024) + _c_read_attr(self._channel, self._name_ascii, buf, len(buf)) + return buf.value.decode('ascii') + + def _Attr__write(self, value): + _c_write_attr(self._channel, self._name_ascii, value.encode('ascii')) + +class DeviceAttr(_Attr): + """Represents an attribute of an IIO device.""" + + def __init__(self, device, name): + super(DeviceAttr, self).__init__(name) + self._device = device + + def _Attr__read(self): + buf = create_string_buffer(1024) + _d_read_attr(self._device, self._name_ascii, buf, len(buf)) + return buf.value.decode('ascii') + + def _Attr__write(self, value): + _d_write_attr(self._device, self._name_ascii, value.encode('ascii')) + +class DeviceDebugAttr(DeviceAttr): + """Represents a debug attribute of an IIO device.""" + + def __init__(self, device, name): + super(DeviceDebugAttr, self).__init__(device, name) + + def _Attr__read(self): + buf = create_string_buffer(1024) + _d_read_debug_attr(self._device, self._name_ascii, buf, len(buf)) + return buf.value.decode('ascii') + + def _Attr__write(self, value): + _d_write_debug_attr(self._device, self._name_ascii, value.encode('ascii')) + +class Channel(object): + def __init__(self, _channel): + self._channel = _channel + self._attrs = { name : ChannelAttr(_channel, name) for name in \ + [_c_get_attr(_channel, x).decode('ascii') for x in range(0, _c_attr_count(_channel))] } + self._id = _c_get_id(self._channel).decode('ascii') + + name_raw = _c_get_name(self._channel) + self._name = name_raw.decode('ascii') if name_raw is not None else None + self._output = _c_is_output(self._channel) + self._scan_element = _c_is_scan_element(self._channel) + + def read(self, buf, raw = False): + """ + Extract the samples corresponding to this channel from the given iio.Buffer object. + + parameters: + buf: type=iio.Buffer + A valid instance of the iio.Buffer class + raw: type=bool + If set to True, the samples are not converted from their + native format to their host format + + returns: type=bytearray + An array containing the samples for this channel + """ + array = bytearray(buf._length) + mytype = c_char * len(array) + c_array = mytype.from_buffer(array) + if raw: + length = _c_read_raw(self._channel, buf._buffer, c_array, len(array)) + else: + length = _c_read(self._channel, buf._buffer, c_array, len(array)) + return array[:length] + + def write(self, buf, array, raw = False): + """ + Write the specified array of samples corresponding to this channel into the given iio.Buffer object. + + parameters: + buf: type=iio.Buffer + A valid instance of the iio.Buffer class + array: type=bytearray + The array containing the samples to copy + raw: type=bool + If set to True, the samples are not converted from their + host format to their native format + + returns: type=int + The number of bytes written + """ + mytype = c_char * len(array) + c_array = mytype.from_buffer(array) + if raw: + return _c_write_raw(self._channel, buf._buffer, c_array, len(array)) + else: + return _c_write(self._channel, buf._buffer, c_array, len(array)) + + id = property(lambda self: self._id, None, None, + "An identifier of this channel.\n\tNote that it is possible that two channels have the same ID, if one is an input channel and the other is an output channel.\n\ttype=str") + name = property(lambda self: self._name, None, None, + "The name of this channel.\n\ttype=str") + attrs = property(lambda self: self._attrs, None, None, + "List of attributes for this channel.\n\ttype=dict of iio.ChannelAttr") + output = property(lambda self: self._output, None, None, + "Contains True if the channel is an output channel, False otherwise.\n\ttype=bool") + scan_element = property(lambda self: self._scan_element, None, None, + "Contains True if the channel is a scan element, False otherwise.\n\tIf a channel is a scan element, then it is possible to enable it and use it for I/O operations.\n\ttype=bool") + enabled = property(lambda self: _c_is_enabled(self._channel), \ + lambda self, x: _c_enable(self._channel) if x else _c_disable(self._channel), + None, "Configured state of the channel\n\ttype=bool") + +class Buffer(object): + """The class used for all I/O operations.""" + + def __init__(self, device, samples_count, cyclic = False): + """ + Initializes a new instance of the Buffer class. + + parameters: + device: type=iio.Device + The iio.Device object that represents the device where the I/O + operations will be performed + samples_count: type=int + The size of the buffer, in samples + circular: type=bool + If set to True, the buffer is circular + + returns: type=iio.Buffer + An new instance of this class + """ + try: + self._buffer = _create_buffer(device._device, samples_count, cyclic) + except: + self._buffer = None + raise + self._length = samples_count * device.sample_size + self._samples_count = samples_count + + self._ctx = device.ctx() + # Holds a reference to the corresponding IIO Context. This ensures that + # every iio.Buffer object is destroyed before its corresponding IIO Context. + + def __del__(self): + if self._buffer is not None: + _buffer_destroy(self._buffer) + + def __len__(self): + """The size of this buffer, in bytes.""" + return self._length + + def refill(self): + """Fetch a new set of samples from the hardware.""" + _buffer_refill(self._buffer) + + def push(self, samples_count = None): + """ + Submit the samples contained in this buffer to the hardware. + + parameters: + samples_count: type=int + The number of samples to submit, default = full buffer + """ + _buffer_push_partial(self._buffer, samples_count or self._samples_count) + + def read(self): + """ + Retrieve the samples contained inside the Buffer object. + + returns: type=bytearray + An array containing the samples + """ + + start = _buffer_start(self._buffer) + end = _buffer_end(self._buffer) + array = bytearray(end - start) + mytype = c_char * len(array) + c_array = mytype.from_buffer(array) + _memmove(c_array, start, len(array)) + return array + + def write(self, array): + """ + Copy the given array of samples inside the Buffer object. + + parameters: + array: type=bytearray + The array containing the samples to copy + + returns: type=int + The number of bytes written into the buffer + """ + start = _buffer_start(self._buffer) + end = _buffer_end(self._buffer) + length = end - start + if length > len(array): + length = len(array) + mytype = c_char * len(array) + c_array = mytype.from_buffer(array) + _memmove(start, c_array, length) + return length + +class _DeviceOrTrigger(object): + def __init__(self, _device): + self._device = _device + self._attrs = { name : DeviceAttr(_device, name) for name in \ + [_d_get_attr(_device, x).decode('ascii') for x in range(0, _d_attr_count(_device))] } + self._debug_attrs = { name: DeviceDebugAttr(_device, name) for name in \ + [_d_get_debug_attr(_device, x).decode('ascii') for x in range(0, _d_debug_attr_count(_device))] } + + # TODO(pcercuei): Use a dictionary for the channels. + chans = [ Channel(_get_channel(self._device, x)) + for x in range(0, _channels_count(self._device)) ] + self._channels = sorted(chans, key=lambda c: c.id) + self._id = _d_get_id(self._device).decode('ascii') + + name_raw = _d_get_name(self._device) + self._name = name_raw.decode('ascii') if name_raw is not None else None + + def reg_write(self, reg, value): + """ + Set a value to one register of this device. + + parameters: + reg: type=int + The register address + value: type=int + The value that will be used for this register + """ + _d_reg_write(self._device, reg, value) + + def reg_read(self, reg): + """ + Read the content of a register of this device. + + parameters: + reg: type=int + The register address + + returns: type=int + The value of the register + """ + value = c_uint() + _d_reg_read(self._device, reg, _byref(value)) + return value.value + + def find_channel(self, name_or_id, is_output = False): + """ + + Find a IIO channel by its name or ID. + + parameters: + name_or_id: type=str + The name or ID of the channel to find + is_output: type=bool + Set to True to search for an output channel + + returns: type=iio.Device or type=iio.Trigger + The IIO Device + """ + return next((x for x in self.channels \ + if name_or_id == x.name or name_or_id == x.id and \ + x.output == is_output), None) + + def set_kernel_buffers_count(self, count): + """ + + Set the number of kernel buffers to use with the specified device. + + parameters: + count: type=int + The number of kernel buffers + + """ + return _d_set_buffers_count(self._device, count) + + @property + def sample_size(self): + """ + Current sample size of this device. + type: int + + The sample size varies each time channels get enabled or disabled.""" + return _get_sample_size(self._device) + + id = property(lambda self: self._id, None, None, + "An identifier of this device, only valid in this IIO context.\n\ttype=str") + name = property(lambda self: self._name, None, None, + "The name of this device.\n\ttype=str") + attrs = property(lambda self: self._attrs, None, None, + "List of attributes for this IIO device.\n\ttype=dict of iio.DeviceAttr") + debug_attrs = property(lambda self: self._debug_attrs, None, None, + "List of debug attributes for this IIO device.\n\ttype=dict of iio.DeviceDebugAttr") + channels = property(lambda self: self._channels, None, None, + "List of channels available with this IIO device.\n\ttype=list of iio.Channel objects") + +class Trigger(_DeviceOrTrigger): + """Contains the representation of an IIO device that can act as a trigger.""" + + def __init__(self, _device): + super(Trigger, self).__init__(_device) + + def _get_rate(self): + return int(self._attrs['frequency'].value) + + def _set_rate(self, value): + self._attrs['frequency'].value = str(value) + + frequency = property(_get_rate, _set_rate, None, + "Configured frequency (in Hz) of this trigger\n\ttype=int") + +class Device(_DeviceOrTrigger): + """Contains the representation of an IIO device.""" + + def __init__(self, ctx, _device): + super(Device, self).__init__(_device) + self.ctx = weakref.ref(ctx) + + def _set_trigger(self, trigger): + _d_set_trigger(self._device, trigger._device if trigger else None) + + def _get_trigger(self): + value = _Device() + _d_get_trigger(self._device, _byref(value)) + + for dev in self.ctx()._devices: + if value == dev._device: + return dev + return None + + trigger = property(_get_trigger, _set_trigger, None, \ + "Contains the configured trigger for this IIO device.\n\ttype=iio.Trigger") + +class Context(object): + """Contains the representation of an IIO context.""" + + def __init__(self, _context=None): + """ + Initializes a new instance of the Context class, using the local or the network backend of the IIO library. + + returns: type=iio.Context + An new instance of this class + + This function will create a network context if the IIOD_REMOTE + environment variable is set to the hostname where the IIOD server runs. + If set to an empty string, the server will be discovered using ZeroConf. + If the environment variable is not set, a local context will be created instead. + """ + self._context = None + + if(_context is None): + self._context = _new_default() + elif type(_context) is str or type(_context) is unicode: + self._context = _new_uri(_context.encode('ascii')) + else: + self._context = _context + + self._attrs = {} + for x in range(0, _get_attrs_count(self._context)): + str1 = c_char_p() + str2 = c_char_p() + _get_attr(self._context, x, _byref(str1), _byref(str2)) + self._attrs[str1.value.decode('ascii')] = str2.value.decode('ascii') + + # TODO(pcercuei): Use a dictionary for the devices. + self._devices = [ Trigger(dev) if _d_is_trigger(dev) else Device(self, dev) for dev in \ + [ _get_device(self._context, x) for x in range(0, _devices_count(self._context)) ]] + self._name = _get_name(self._context).decode('ascii') + self._description = _get_description(self._context).decode('ascii') + self._xml = _get_xml(self._context).decode('ascii') + + major = c_uint() + minor = c_uint() + buf = create_string_buffer(8) + _get_version(self._context, _byref(major), _byref(minor), buf) + self._version = (major.value, minor.value, buf.value.decode('ascii') ) + + def __del__(self): + if(self._context is not None): + _destroy(self._context) + + def set_timeout(self, timeout): + """ + Set a timeout for I/O operations. + + parameters: + timeout: type=int + The timeout value, in milliseconds + """ + _set_timeout(self._context, timeout) + + def clone(self): + """ + Clone this instance. + + returns: type=iio.LocalContext + An new instance of this class + """ + return Context(_clone(self._context)) + + def find_device(self, name_or_id): + """ + + Find a IIO device by its name or ID. + + parameters: + name_or_id: type=str + The name or ID of the device to find + + returns: type=iio.Device or type=iio.Trigger + The IIO Device + """ + return next((x for x in self.devices \ + if name_or_id == x.name or name_or_id == x.id), None) + + name = property(lambda self: self._name, None, None, \ + "Name of this IIO context.\n\ttype=str") + description = property(lambda self: self._description, None, None, \ + "Description of this IIO context.\n\ttype=str") + xml = property(lambda self: self._xml, None, None, \ + "XML representation of the current context.\n\ttype=str") + version = property(lambda self: self._version, None, None, \ + "Version of the backend.\n\ttype=(int, int, str)") + attrs = property(lambda self: self._attrs, None, None, \ + "List of context-specific attributes\n\ttype=dict of str objects") + devices = property(lambda self: self._devices, None, None, \ + "List of devices contained in this context.\n\ttype=list of iio.Device and iio.Trigger objects") + +class LocalContext(Context): + def __init__(self): + """ + Initializes a new instance of the Context class, using the local backend of the IIO library. + + returns: type=iio.LocalContext + An new instance of this class + """ + ctx = _new_local() + super(LocalContext, self).__init__(ctx) + +class XMLContext(Context): + def __init__(self, xmlfile): + """ + Initializes a new instance of the Context class, using the XML backend of the IIO library. + + parameters: + xmlfile: type=str + Filename of the XML file to build the context from + + returns: type=iio.XMLContext + An new instance of this class + """ + ctx = _new_xml(xmlfile.encode('ascii')) + super(XMLContext, self).__init__(ctx) + +class NetworkContext(Context): + def __init__(self, hostname = None): + """ + Initializes a new instance of the Context class, using the network backend of the IIO library. + + parameters: + hostname: type=str + Hostname, IPv4 or IPv6 address where the IIO Daemon is running + + returns: type=iio.NetworkContext + An new instance of this class + """ + ctx = _new_network(hostname.encode('ascii') if hostname is not None else None) + super(NetworkContext, self).__init__(ctx) + +def scan_contexts(): + d = dict() + ptr = _POINTER(_ContextInfoPtr)() + + ctx = _create_scan_context(None, 0) + nb = _get_context_info_list(ctx, _byref(ptr)); + + for i in range(0, nb): + d[_context_info_get_uri(ptr[i]).decode('ascii')] = _context_info_get_description(ptr[i]).decode('ascii') + + _context_info_list_free(ptr) + _destroy_scan_context(ctx) + return d diff --git a/bindings/python/setup.py.cmakein b/bindings/python/setup.py.cmakein new file mode 100644 index 0000000..4cf1b50 --- /dev/null +++ b/bindings/python/setup.py.cmakein @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# +# Copyright (C) 2015 Analog Devices, Inc. +# Author: Paul Cercueil <paul.cercueil@analog.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +from distutils.core import setup + +setup(name='libiio', + version='${VERSION}', + package_dir={'': '${CMAKE_CURRENT_SOURCE_DIR}'}, + description='Library to use the Industrial IO devices', + url='https://github.com/analogdevicesinc/libiio', + py_modules=['iio'], + ) |