1 /*
2  * libiio - Library for interfacing industrial I/O (IIO) devices
3  *
4  * Copyright (C) 2015 Analog Devices, Inc.
5  * Author: Paul Cercueil <paul.cercueil@analog.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * */
18 
19 using System;
20 using System.Collections.Generic;
21 using System.Linq;
22 using System.Runtime.InteropServices;
23 using System.Text;
24 using System.Threading.Tasks;
25 
26 namespace iio
27 {
28     public class Version
29     {
30         public readonly uint major;
31         public readonly uint minor;
32         public readonly string git_tag;
33 
Version(uint major, uint minor, string git_tag)34         internal Version(uint major, uint minor, string git_tag)
35         {
36             this.major = major;
37             this.minor = minor;
38             this.git_tag = git_tag;
39         }
40     }
41 
42     /// <summary><see cref="iio.Context"/> class:
43     /// Contains the representation of an IIO context.</summary>
44     public class Context : IDisposable
45     {
46         internal IntPtr ctx;
47 
48         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_create_network_context( [In()][MarshalAs(UnmanagedType.LPStr)] string hostname )49         private static extern IntPtr iio_create_network_context(
50             [In()][MarshalAs(UnmanagedType.LPStr)] string hostname
51         );
52 
53         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_create_context_from_uri( [In()][MarshalAs(UnmanagedType.LPStr)] string uri )54         private static extern IntPtr iio_create_context_from_uri(
55             [In()][MarshalAs(UnmanagedType.LPStr)] string uri
56         );
57 
58         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_create_default_context()59         private static extern IntPtr iio_create_default_context();
60 
61         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_create_local_context()62         private static extern IntPtr iio_create_local_context();
63 
64         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_destroy(IntPtr ctx)65         private static extern void iio_context_destroy(IntPtr ctx);
66 
67         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_name(IntPtr ctx)68         private static extern IntPtr iio_context_get_name(IntPtr ctx);
69 
70         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_description(IntPtr ctx)71         private static extern IntPtr iio_context_get_description(IntPtr ctx);
72 
73         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_xml(IntPtr ctx)74         private static extern IntPtr iio_context_get_xml(IntPtr ctx);
75 
76         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_library_get_version(ref uint major, ref uint minor, [Out()] StringBuilder git_tag)77         private static extern void iio_library_get_version(ref uint major, ref uint minor, [Out()] StringBuilder git_tag);
78 
79         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_version(IntPtr ctx, ref uint major, ref uint minor, [Out()] StringBuilder git_tag)80         private static extern int iio_context_get_version(IntPtr ctx, ref uint major, ref uint minor, [Out()] StringBuilder git_tag);
81 
82         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_devices_count(IntPtr ctx)83         private static extern uint iio_context_get_devices_count(IntPtr ctx);
84 
85         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_device(IntPtr ctx, uint index)86         private static extern IntPtr iio_context_get_device(IntPtr ctx, uint index);
87 
88         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
89         [return: MarshalAs(UnmanagedType.I1)]
iio_device_is_trigger(IntPtr dev)90         private static extern bool iio_device_is_trigger(IntPtr dev);
91 
92         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_set_timeout(IntPtr ctx, uint timeout_ms)93         private static extern int iio_context_set_timeout(IntPtr ctx, uint timeout_ms);
94 
95         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_clone(IntPtr ctx)96         private static extern IntPtr iio_context_clone(IntPtr ctx);
97 
98         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_attrs_count(IntPtr ctx)99         private static extern uint iio_context_get_attrs_count(IntPtr ctx);
100 
101         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_get_attr(IntPtr ctx, uint index, IntPtr name_ptr, IntPtr value_ptr)102         private static extern int iio_context_get_attr(IntPtr ctx, uint index, IntPtr name_ptr, IntPtr value_ptr);
103 
104         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_find_device(IntPtr ctx, [In] string name)105         private static extern IntPtr iio_context_find_device(IntPtr ctx, [In] string name);
106 
107         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_context_info_get_description(IntPtr info)108         private static extern IntPtr iio_context_info_get_description(IntPtr info);
109 
110         /// <summary>A XML representation of the current context.</summary>
111         public readonly string xml;
112 
113         /// <summary>The name of the current context.</summary>
114         public readonly string name;
115 
116         /// <summary>Retrieve a human-readable information string about the current context.</summary>
117         public readonly string description;
118         /// <summary>Retrieve a information about the version context.</summary>
119         public readonly Version library_version, backend_version;
120 
121         /// <summary>A <c>List</c> of all the IIO devices present on the current context.</summary>
122         public readonly List<Device> devices;
123 
124         /// <summary>A <c>Dictionary</c> of all the attributes of the current channel. (key, value) = (name, value)</summary>
125         public Dictionary<string, string> attrs { get; private set; }
126 
127         /// <summary>Initializes a new instance of the <see cref="iio.Context"/> class,
128         /// using the provided URI. For compatibility with existing code, providing
129         /// an IP address or a hostname here will automatically create a network
130         /// context.</summary>
131         /// <param name="uri">URI to use for the IIO context creation</param>
132         /// <returns>an instance of the <see cref="iio.Context"/> class</returns>
133         /// <exception cref="System.Exception">The IIO context could not be created.</exception>
Context(string uri)134         public Context(string uri) : this(getContextFromString(uri)) {}
135 
136         /// <summary>Initializes a new instance of the <see cref="iio.Context"/> class,
137         /// using the local or the network backend of the IIO library.</summary>
138         /// <remarks>This function will create a network context if the IIOD_REMOTE
139         /// environment variable is set to the hostname where the IIOD server runs.
140         /// If set to an empty string, the server will be discovered using ZeroConf.
141         /// If the environment variable is not set, a local context will be created
142         /// instead.</remarks>
143         /// <exception cref="System.Exception">The IIO context could not be created.</exception>
Context()144         public Context() : this(iio_create_default_context()) {}
145 
getContextFromString(string str)146         private static IntPtr getContextFromString(string str)
147         {
148             IntPtr ptr = iio_create_context_from_uri(str);
149             if (ptr == IntPtr.Zero)
150             {
151                 ptr = iio_create_network_context(str);
152             }
153             return ptr;
154         }
155 
Context(IntPtr ctx)156         internal Context(IntPtr ctx)
157         {
158             this.ctx = ctx;
159 
160             if (ctx == IntPtr.Zero)
161             {
162                 throw new Exception("Unable to create IIO context");
163             }
164 
165             uint nb_devices = iio_context_get_devices_count(ctx);
166 
167             devices = new List<Device>();
168             for (uint i = 0; i < nb_devices; i++)
169             {
170                 IntPtr ptr = iio_context_get_device(ctx, i);
171                 if (iio_device_is_trigger(ptr))
172                 {
173                     devices.Add(new Trigger(this, ptr));
174                 }
175                 else
176                 {
177                     devices.Add(new Device(this, ptr));
178                 }
179             }
180 
181             xml = Marshal.PtrToStringAnsi(iio_context_get_xml(ctx));
182             name = Marshal.PtrToStringAnsi(iio_context_get_name(ctx));
183             description = Marshal.PtrToStringAnsi(iio_context_get_description(ctx));
184 
185             uint major = 0;
186             uint minor = 0;
187             StringBuilder builder = new StringBuilder(8);
188             iio_library_get_version(ref major, ref minor, builder);
189             library_version = new Version(major, minor, builder.ToString());
190 
191             major = 0;
192             minor = 0;
193             builder.Clear();
194             int err = iio_context_get_version(ctx, ref major, ref minor, builder);
195             if (err < 0)
196             {
197                 throw new Exception("Unable to read backend version");
198             }
199             backend_version = new Version(major, minor, builder.ToString());
200 
201             attrs = new Dictionary<string, string>();
202 
203             for (uint i = 0; i < iio_context_get_attrs_count(ctx); i++)
204             {
205                 string attr_name = "";
206                 GCHandle name_handle = GCHandle.Alloc(attr_name, GCHandleType.Pinned);
207                 IntPtr name_ptr = GCHandle.ToIntPtr(name_handle);
208                 string attr_value = "";
209                 GCHandle value_handle = GCHandle.Alloc(attr_value, GCHandleType.Pinned);
210                 IntPtr value_ptr = GCHandle.ToIntPtr(value_handle);
211 
212                 iio_context_get_attr(ctx, i, name_ptr, value_ptr);
213                 attr_name = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(name_ptr));
214                 attr_value = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(value_ptr));
215 
216                 attrs[attr_name] = attr_value;
217             }
218         }
219 
~Context()220         ~Context()
221         {
222             if (ctx != IntPtr.Zero)
223             {
224                 Dispose(false);
225             }
226         }
227 
228         /// <summary>Clone this instance.</summary>
clone()229         public Context clone()
230         {
231             return new Context(iio_context_clone(this.ctx));
232         }
233 
234         /// <summary>Get the <see cref="iio.Device"/> object of the specified name.</summary>
235         /// <param name="name">Name or ID of the device to look for</param>
236         /// <exception cref="System.Exception">The IIO device with the specified
237         /// name or ID could not be found in the current context.</exception>
get_device(string name)238         public Device get_device(string name)
239         {
240             foreach (Device each in devices) {
241                 if (each.name.CompareTo(name) == 0 ||
242                             each.id.CompareTo(name) == 0)
243                 {
244                     return each;
245                 }
246             }
247 
248             throw new Exception("Device " + name + " not found");
249         }
250 
251         /// <summary>Set a timeout for I/O operations.</summary>
252         /// <param name="timeout">The timeout value, in milliseconds</param>
253         /// <exception cref="System.Exception">The timeout could not be applied.</exception>
set_timeout(uint timeout)254         public void set_timeout(uint timeout)
255         {
256             int ret = iio_context_set_timeout(ctx, timeout);
257             if (ret < 0)
258             {
259                 throw new Exception("Unable to set timeout");
260             }
261         }
262 
263         /// <summary>Releases all resource used by the <see cref="iio.Context"/> object.</summary>
264         /// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="iio.Context"/>. The
265         /// <see cref="Dispose"/> method leaves the <see cref="iio.Context"/> in an unusable state. After calling
266         /// <see cref="Dispose"/>, you must release all references to the <see cref="iio.Context"/> so the garbage
267         /// collector can reclaim the memory that the <see cref="iio.Context"/> was occupying.</remarks>
Dispose()268         public void Dispose()
269         {
270             Dispose(true);
271         }
272 
Dispose(bool clean)273         private void Dispose(bool clean)
274         {
275             if (ctx != IntPtr.Zero)
276             {
277                 if (clean)
278                 {
279                     GC.SuppressFinalize(this);
280                 }
281                 iio_context_destroy(ctx);
282                 ctx = IntPtr.Zero;
283             }
284         }
285 
286         /// <summary>Finds the device with the given name from the current context.</summary>
287         /// <param name="device">The name of the device.</param>
288         /// <exception cref="System.Exception">There is no device with the given name.</exception>
find_device(string device)289         public Device find_device(string device)
290         {
291             IntPtr dev = iio_context_find_device(ctx, device);
292 
293             if (dev == IntPtr.Zero)
294             {
295                 throw new Exception("There is no device with the given name!");
296             }
297 
298             return new Device(this, dev);
299         }
300     }
301 }
302