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     /// <summary><see cref="iio.Device"/> class:
29     /// Contains the representation of an IIO device.</summary>
30     public class Device
31     {
32         private class DeviceAttr : Attr
33         {
34             internal IntPtr dev;
35 
36             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_attr_read(IntPtr dev, [In()] string name, [Out()] StringBuilder val, uint len)37             private static extern int iio_device_attr_read(IntPtr dev, [In()] string name, [Out()] StringBuilder val, uint len);
38 
39             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_attr_write(IntPtr dev, [In()] string name, [In()] string val)40             private static extern int iio_device_attr_write(IntPtr dev, [In()] string name, [In()] string val);
41 
DeviceAttr(IntPtr dev, string name)42             public DeviceAttr(IntPtr dev, string name) : base(name)
43             {
44                 this.dev = dev;
45             }
46 
read()47             public override string read()
48             {
49                 StringBuilder builder = new StringBuilder(1024);
50                 int err = iio_device_attr_read(dev, name, builder, 1024);
51                 if (err < 0)
52                 {
53                     throw new Exception("Unable to read device attribute " + err);
54                 }
55                 return builder.ToString();
56             }
57 
write(string str)58             public override void write(string str)
59             {
60                 int err = iio_device_attr_write(dev, name, str);
61                 if (err < 0)
62                 {
63                     throw new Exception("Unable to write device attribute " + err);
64                 }
65             }
66         }
67 
68         private class DeviceDebugAttr : Attr
69         {
70             private IntPtr dev;
71 
72             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_debug_attr_read(IntPtr dev, [In()] string name, [Out()] StringBuilder val, uint len)73             private static extern int iio_device_debug_attr_read(IntPtr dev, [In()] string name, [Out()] StringBuilder val, uint len);
74 
75             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_debug_attr_write(IntPtr dev, [In()] string name, [In()] string val)76             private static extern int iio_device_debug_attr_write(IntPtr dev, [In()] string name, [In()] string val);
77 
DeviceDebugAttr(IntPtr dev, string name)78             public DeviceDebugAttr(IntPtr dev, string name) : base(name)
79             {
80                 this.dev = dev;
81             }
82 
read()83             public override string read()
84             {
85                 StringBuilder builder = new StringBuilder(1024);
86                 int err = iio_device_debug_attr_read(dev, name, builder, 1024);
87                 if (err < 0)
88                 {
89                     throw new Exception("Unable to read debug attribute " + err);
90                 }
91                 return builder.ToString();
92             }
93 
write(string str)94             public override void write(string str)
95             {
96                 int err = iio_device_debug_attr_write(dev, name, str);
97                 if (err < 0)
98                 {
99                     throw new Exception("Unable to write debug attribute " + err);
100                 }
101             }
102         }
103 
104         private class DeviceBufferAttr : Attr
105         {
106             private IntPtr dev;
107 
108             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_buffer_attr_read(IntPtr dev, [In] string name, [Out] StringBuilder val, uint len)109             private static extern int iio_device_buffer_attr_read(IntPtr dev, [In] string name, [Out] StringBuilder val, uint len);
110 
111             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_buffer_attr_write(IntPtr dev, [In] string name, [In] string val)112             private static extern int iio_device_buffer_attr_write(IntPtr dev, [In] string name, [In] string val);
113 
DeviceBufferAttr(IntPtr dev, string name)114             public DeviceBufferAttr(IntPtr dev, string name) : base(name)
115             {
116                 this.dev = dev;
117             }
118 
read()119             public override string read()
120             {
121                 StringBuilder builder = new StringBuilder(16384);
122                 int err = iio_device_buffer_attr_read(dev, name, builder, 16384);
123                 if (err < 0)
124                 {
125                     throw new Exception("Unable to read buffer attribute " + err);
126                 }
127                 return builder.ToString();
128             }
129 
write(string str)130             public override void write(string str)
131             {
132                 int err = iio_device_buffer_attr_write(dev, name, str);
133                 if (err < 0)
134                 {
135                     throw new Exception("Unable to write buffer attribute " + err);
136                 }
137             }
138         }
139 
140         internal Context ctx;
141 
142         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_id(IntPtr dev)143         private static extern IntPtr iio_device_get_id(IntPtr dev);
144 
145         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_name(IntPtr dev)146         private static extern IntPtr iio_device_get_name(IntPtr dev);
147 
148         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_channels_count(IntPtr dev)149         private static extern uint iio_device_get_channels_count(IntPtr dev);
150 
151         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_channel(IntPtr dev, uint index)152         private static extern IntPtr iio_device_get_channel(IntPtr dev, uint index);
153 
154         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_attrs_count(IntPtr dev)155         private static extern uint iio_device_get_attrs_count(IntPtr dev);
156 
157         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_debug_attrs_count(IntPtr dev)158         private static extern uint iio_device_get_debug_attrs_count(IntPtr dev);
159 
160         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_buffer_attrs_count(IntPtr dev)161         private static extern uint iio_device_get_buffer_attrs_count(IntPtr dev);
162 
163         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_attr(IntPtr dev, uint index)164         private static extern IntPtr iio_device_get_attr(IntPtr dev, uint index);
165 
166         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_debug_attr(IntPtr dev, uint index)167         private static extern IntPtr iio_device_get_debug_attr(IntPtr dev, uint index);
168 
169         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_buffer_attr(IntPtr dev, uint index)170         private static extern IntPtr iio_device_get_buffer_attr(IntPtr dev, uint index);
171 
172         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_trigger(IntPtr dev, IntPtr triggerptr)173         private static extern int iio_device_get_trigger(IntPtr dev, IntPtr triggerptr);
174 
175         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_set_trigger(IntPtr dev, IntPtr trigger)176         private static extern int iio_device_set_trigger(IntPtr dev, IntPtr trigger);
177 
178         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_sample_size(IntPtr dev)179         private static extern int iio_device_get_sample_size(IntPtr dev);
180 
181         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_reg_write(IntPtr dev, uint addr, uint value)182         private static extern int iio_device_reg_write(IntPtr dev, uint addr, uint value);
183 
184         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_reg_read(IntPtr dev, uint addr, ref uint value)185         private static extern int iio_device_reg_read(IntPtr dev, uint addr, ref uint value);
186 
187         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_context(IntPtr dev)188         private static extern IntPtr iio_device_get_context(IntPtr dev);
189 
190         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_set_kernel_buffers_count(IntPtr dev, uint nb)191         private static extern int iio_device_set_kernel_buffers_count(IntPtr dev, uint nb);
192 
193         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_find_buffer_attr(IntPtr dev, [In] string name)194         private static extern IntPtr iio_device_find_buffer_attr(IntPtr dev, [In] string name);
195 
196         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_find_debug_attr(IntPtr dev, [In] string name)197         private static extern IntPtr iio_device_find_debug_attr(IntPtr dev, [In] string name);
198 
199         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_find_attr(IntPtr dev, [In] string name)200         private static extern IntPtr iio_device_find_attr(IntPtr dev, [In] string name);
201 
202         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_find_channel(IntPtr dev, [In] string name, [In] bool output)203         private static extern IntPtr iio_device_find_channel(IntPtr dev, [In] string name, [In] bool output);
204 
205         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_identify_filename(IntPtr dev, [In] string filename, out IntPtr chn_ptr, out IntPtr attr)206         private static extern int iio_device_identify_filename(IntPtr dev, [In] string filename, out IntPtr chn_ptr, out IntPtr attr);
207 
208         internal IntPtr dev;
209 
210         /// <summary>An identifier of this device.</summary>
211         /// <remarks>The identifier is only valid in this IIO context</remarks>
212         public readonly string id;
213 
214         /// <summary>The name of this device.</summary>
215         public readonly string name;
216 
217         /// <summary>A <c>list</c> of all the attributes that this device has.</summary>
218         public readonly List<Attr> attrs;
219 
220         /// <summary>A <c>list</c> of all the debug attributes that this device has.</summary>
221         public readonly List<Attr> debug_attrs;
222 
223         /// <summary>A <c>list</c> of all the buffer attributes that this device has.</summary>
224         public List<Attr> buffer_attrs { get; private set; }
225 
226         /// <summary>A <c>list</c> of all the <see cref="iio.Channel"/> objects that this device possesses.</summary>
227         public readonly List<Channel> channels;
228 
Device(Context ctx, IntPtr dev)229         internal Device(Context ctx, IntPtr dev)
230         {
231             this.ctx = ctx;
232             this.dev = dev;
233             channels = new List<Channel>();
234             attrs = new List<Attr>();
235             debug_attrs = new List<Attr>();
236             buffer_attrs = new List<Attr>();
237 
238             uint nb_channels = iio_device_get_channels_count(dev);
239             uint nb_attrs = iio_device_get_attrs_count(dev);
240             uint nb_debug_attrs = iio_device_get_debug_attrs_count(dev);
241             uint nb_buffer_attrs = iio_device_get_buffer_attrs_count(dev);
242 
243             for (uint i = 0; i < nb_channels; i++)
244             {
245                 channels.Add(new Channel(iio_device_get_channel(dev, i)));
246             }
247 
248             for (uint i = 0; i < nb_attrs; i++)
249             {
250                 attrs.Add(new DeviceAttr(dev, Marshal.PtrToStringAnsi(iio_device_get_attr(dev, i))));
251             }
252 
253             for (uint i = 0; i < nb_debug_attrs; i++)
254             {
255                 debug_attrs.Add(new DeviceDebugAttr(dev, Marshal.PtrToStringAnsi(iio_device_get_debug_attr(dev, i))));
256             }
257 
258             for (uint i = 0; i < nb_buffer_attrs; i++)
259             {
260                 buffer_attrs.Add(new DeviceBufferAttr(dev, Marshal.PtrToStringAnsi(iio_device_get_buffer_attr(dev, i))));
261             }
262 
263             id = Marshal.PtrToStringAnsi(iio_device_get_id(dev));
264 
265             IntPtr name_ptr = iio_device_get_name(dev);
266             if (name_ptr == IntPtr.Zero)
267             {
268                 name = "";
269             }
270             else
271             {
272                 name = Marshal.PtrToStringAnsi(name_ptr);
273             }
274         }
275 
276         /// <summary>Get the <see cref="iio.Channel"/> object of the specified name.</summary>
277         /// <param name="name">Name or ID of the channel to look for</param>
278         /// <exception cref="System.Exception">The IIO device with the specified
279         /// name or ID could not be found in the current context.</exception>
get_channel(string name)280         public Channel get_channel(string name)
281         {
282             foreach (Channel each in channels)
283             {
284                 if (each.name.CompareTo(name) == 0 ||
285                             each.id.CompareTo(name) == 0)
286                 {
287                     return each;
288                 }
289             }
290 
291             throw new Exception("Channel " + name + " not found");
292         }
293 
294         /// <summary>Affect a trigger to this device.</summary>
295         /// <param name="trig">A valid instance of the <see cref="iio.Trigger"/> class.</param>
296         /// <exception cref="System.Exception">The trigger could not be set.</exception>
set_trigger(Trigger trig)297         public void set_trigger(Trigger trig)
298         {
299             int err = iio_device_set_trigger(this.dev, trig == null ? IntPtr.Zero : trig.dev);
300             if (err < 0)
301             {
302                 throw new Exception("Unable to set trigger: err=" + err);
303             }
304         }
305 
306         /// <summary>Get the current trigger affected to this device.</summary>
307         /// <returns>An instance of the <see cref="iio.Trigger"/> class.</returns>
308         /// <exception cref="System.Exception">The instance could not be retrieved.</exception>
get_trigger()309         public Trigger get_trigger()
310         {
311             IntPtr ptr = (IntPtr)0;
312             int err = iio_device_get_trigger(this.dev, ptr);
313             if (err < 0)
314             {
315                 throw new Exception("Unable to get trigger: err=" + err);
316             }
317 
318             ptr = Marshal.ReadIntPtr(ptr);
319 
320             foreach (Trigger trig in ctx.devices)
321             {
322                 if (trig.dev == ptr)
323                 {
324                     return trig;
325                 }
326             }
327 
328             return null;
329         }
330 
331         /// <summary>Get the current sample size of the device.</summary>
332         /// <remarks>The sample size varies each time channels get enabled or disabled.</remarks>
333         /// <exception cref="System.Exception">Internal error. Please report any bug.</exception>
get_sample_size()334         public uint get_sample_size()
335         {
336             int ret = iio_device_get_sample_size(dev);
337             if (ret < 0)
338             {
339                 throw new Exception("Internal error. Please report any bug.");
340             }
341             return (uint) ret;
342         }
343         /// <summary>Set a value to one register of this device.</summary>
344         /// <param name="addr">The address of the register concerned.</param>
345         /// <param name="value">The value that will be used for this register.</param>
346         /// <exception cref="System.Exception">The register could not be written.</exception>
reg_write(uint addr, uint value)347         public void reg_write(uint addr, uint value)
348         {
349             int err = iio_device_reg_write(dev, addr, value);
350             if (err < 0)
351             {
352                 throw new Exception("Unable to write register");
353             }
354         }
355 
356         /// <summary>Read the content of a register of this device.</summary>
357         /// <param name="addr">The address of the register concerned.</param>
358         /// <exception cref="System.Exception">The register could not be read.</exception>
reg_read(uint addr)359         public uint reg_read(uint addr)
360         {
361             uint value = 0;
362             int err = iio_device_reg_read(dev, addr, ref value);
363             if (err < 0)
364             {
365                 throw new Exception("Unable to read register");
366             }
367             return value;
368         }
369 
370         /// <summary>Sets the number of active kernel buffers for this device.</summary>
371         /// <param name="nb">The number of kernel buffers.</param>
set_kernel_buffers_count(uint nb)372         public int set_kernel_buffers_count(uint nb)
373         {
374             return iio_device_set_kernel_buffers_count(dev, nb);
375         }
376 
377         /// <summary>Gets the context of the current device.</summary>
378         /// <returns>An instance of the <see cref="iio.Context"/> class.</returns>
get_context()379         public Context get_context()
380         {
381             return new Context(iio_device_get_context(dev));
382         }
383 
384         /// <summary>Finds the channel with the given name from the current device.</summary>
385         /// <param name="channel">The name of the channel.</param>
386         /// <param name="output">true if you are looking for an output channel, otherwise false.</param>
387         /// <returns>An instance of the <see cref="iio.Channel"/> class.</returns>
388         /// <exception cref="System.Exception">There is no channel with the given name.</exception>
find_channel(string channel, bool output)389         public Channel find_channel(string channel, bool output)
390         {
391             IntPtr chn = iio_device_find_channel(dev, channel, output);
392 
393             if (chn == IntPtr.Zero)
394             {
395                 throw new Exception("There is no channel with the given name!");
396             }
397 
398             return new Channel(chn);
399         }
400 
401         /// <summary>Finds the attribute with the given name from the current device.</summary>
402         /// <param name="attribute">The name of the attribute.</param>
403         /// <returns>An instance of the <see cref="iio.Device.DeviceAttr"/> class.</returns>
404         /// <exception cref="System.Exception">There is no attribute with the given name.</exception>
find_attribute(string attribute)405         public Attr find_attribute(string attribute)
406         {
407             IntPtr attr = iio_device_find_attr(dev, attribute);
408 
409             if (attr == IntPtr.Zero)
410             {
411                 throw new Exception("This device has no attribute with the given name!");
412             }
413 
414             return new DeviceAttr(dev, Marshal.PtrToStringAnsi(attr));
415         }
416 
417         /// <summary>Finds the debug attribute with the given name from the current device.</summary>
418         /// <param name="attribute">The name of the debug attribute.</param>
419         /// <returns>An instance of the <see cref="iio.Device.DeviceDebugAttr"/> class.</returns>
420         /// <exception cref="System.Exception">There is no debug attribute with the given name.</exception>
find_debug_attribute(string attribute)421         public Attr find_debug_attribute(string attribute)
422         {
423             IntPtr attr = iio_device_find_debug_attr(dev, attribute);
424 
425             if (attr == IntPtr.Zero)
426             {
427                 throw new Exception("This device has no debug attribute with the given name!");
428             }
429 
430             return new DeviceDebugAttr(dev, Marshal.PtrToStringAnsi(attr));
431         }
432 
433         /// <summary>Finds the buffer attribute with the given name from the current device.</summary>
434         /// <param name="attribute">The name of the buffer attribute.</param>
435         /// <returns>An instance of the <see cref="iio.Device.DeviceBufferAttr"/> class.</returns>
436         /// <exception cref="System.Exception">There is no attribute with the given name.</exception>
find_buffer_attribute(string attribute)437         public Attr find_buffer_attribute(string attribute)
438         {
439             IntPtr attr = iio_device_find_buffer_attr(dev, attribute);
440 
441             if (attr == IntPtr.Zero)
442             {
443                 throw new Exception("This device has no buffer attribute with the given name!");
444             }
445 
446             return new DeviceBufferAttr(dev, Marshal.PtrToStringAnsi(attr));
447         }
448 
449         /// <summary>Finds the channel attribute coresponding to the given filename from the current device.</summary>
450         /// <param name="filename">The name of the attribute.</param>
451         /// <param name="chn_ptr">Output variable. It will contain a pointer to the resulting <see cref="iio.Channel"/>.</param>
452         /// <param name="attr">Output variable. It will contain a pointer to the resulting <see cref="iio.ChannelAttr"/>.</param>
453         /// <returns>C errorcode if error encountered, otherwise 0.</returns>
identify_filename(string filename, IntPtr chn_ptr, IntPtr attr)454         public int identify_filename(string filename, IntPtr chn_ptr, IntPtr attr)
455         {
456             return iio_device_identify_filename(dev, filename, out chn_ptr, out attr);
457         }
458     }
459 }
460