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.IO;
22 using System.Linq;
23 using System.Runtime.InteropServices;
24 using System.Text;
25 using System.Threading.Tasks;
26 
27 namespace iio
28 {
29     /// <summary><see cref="iio.Channel"/> class:
30     /// Contains the representation of an input or output channel.</summary>
31     public class Channel
32     {
33         private class ChannelAttr : Attr
34         {
35             private IntPtr chn;
36 
37             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_attr_read(IntPtr chn, [In()] string name, [Out()] StringBuilder val, uint len)38             private static extern int iio_channel_attr_read(IntPtr chn, [In()] string name, [Out()] StringBuilder val, uint len);
39 
40             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_attr_write(IntPtr chn, [In()] string name, string val)41             private static extern int iio_channel_attr_write(IntPtr chn, [In()] string name, string val);
42 
43             [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_attr_get_filename(IntPtr chn, [In()] string attr)44             private static extern IntPtr iio_channel_attr_get_filename(IntPtr chn, [In()] string attr);
45 
ChannelAttr(IntPtr chn, string name)46             public ChannelAttr(IntPtr chn, string name) : base(name, Marshal.PtrToStringAnsi(iio_channel_attr_get_filename(chn, name)))
47             {
48                 this.chn = chn;
49             }
50 
read()51             public override string read()
52             {
53                 StringBuilder builder = new StringBuilder(1024);
54                 int err = iio_channel_attr_read(chn, name, builder, (uint) builder.Capacity);
55                 if (err < 0)
56                 {
57                     throw new Exception("Unable to read channel attribute " + err);
58                 }
59                 return builder.ToString();
60             }
61 
write(string str)62             public override void write(string str)
63             {
64                 int err = iio_channel_attr_write(chn, name, str);
65                 if (err < 0)
66                 {
67                     throw new Exception("Unable to write channel attribute " + err);
68                 }
69             }
70         }
71 
72         /// <summary><see cref="iio.Channel.ChannelModifier"/> class:
73         /// Contains the available channel modifiers.</summary>
74         public enum ChannelModifier
75         {
76             IIO_NO_MOD,
77             IIO_MOD_X,
78             IIO_MOD_Y,
79             IIO_MOD_Z,
80             IIO_MOD_X_AND_Y,
81             IIO_MOD_X_AND_Z,
82             IIO_MOD_Y_AND_Z,
83             IIO_MOD_X_AND_Y_AND_Z,
84             IIO_MOD_X_OR_Y,
85             IIO_MOD_X_OR_Z,
86             IIO_MOD_Y_OR_Z,
87             IIO_MOD_X_OR_Y_OR_Z,
88             IIO_MOD_LIGHT_BOTH,
89             IIO_MOD_LIGHT_IR,
90             IIO_MOD_ROOT_SUM_SQUARED_X_Y,
91             IIO_MOD_SUM_SQUARED_X_Y_Z,
92             IIO_MOD_LIGHT_CLEAR,
93             IIO_MOD_LIGHT_RED,
94             IIO_MOD_LIGHT_GREEN,
95             IIO_MOD_LIGHT_BLUE,
96             IIO_MOD_QUATERNION,
97             IIO_MOD_TEMP_AMBIENT,
98             IIO_MOD_TEMP_OBJECT,
99             IIO_MOD_NORTH_MAGN,
100             IIO_MOD_NORTH_TRUE,
101             IIO_MOD_NORTH_MAGN_TILT_COMP,
102             IIO_MOD_NORTH_TRUE_TILT_COMP,
103             IIO_MOD_RUNNING,
104             IIO_MOD_JOGGING,
105             IIO_MOD_WALKING,
106             IIO_MOD_STILL,
107             IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
108             IIO_MOD_I,
109             IIO_MOD_Q,
110             IIO_MOD_CO2,
111             IIO_MOD_VOC,
112             IIO_MOD_LIGHT_UV,
113             IIO_MOD_LIGHT_DUV,
114             IIO_MOD_PM1,
115             IIO_MOD_PM2P5,
116             IIO_MOD_PM4,
117             IIO_MOD_PM10,
118             IIO_MOD_ETHANOL,
119             IIO_MOD_H2
120         }
121 
122         /// <summary><see cref="iio.Channel.ChannelType"/> class:
123         /// Contains the available channel types.</summary>
124         public enum ChannelType
125         {
126             IIO_VOLTAGE,
127             IIO_CURRENT,
128             IIO_POWER,
129             IIO_ACCEL,
130             IIO_ANGL_VEL,
131             IIO_MAGN,
132             IIO_LIGHT,
133             IIO_INTENSITY,
134             IIO_PROXIMITY,
135             IIO_TEMP,
136             IIO_INCLI,
137             IIO_ROT,
138             IIO_ANGL,
139             IIO_TIMESTAMP,
140             IIO_CAPACITANCE,
141             IIO_ALTVOLTAGE,
142             IIO_CCT,
143             IIO_PRESSURE,
144             IIO_HUMIDITYRELATIVE,
145             IIO_ACTIVITY,
146             IIO_STEPS,
147             IIO_ENERGY,
148             IIO_DISTANCE,
149             IIO_VELOCITY,
150             IIO_CONCENTRATION,
151             IIO_RESISTANCE,
152             IIO_PH,
153             IIO_UVINDEX,
154             IIO_ELECTRICALCONDUCTIVITY,
155             IIO_COUNT,
156             IIO_INDEX,
157             IIO_GRAVITY,
158             IIO_POSITIONRELATIVE,
159             IIO_PHASE,
160             IIO_MASSCONCENTRATION,
161             IIO_CHAN_TYPE_UNKNOWN = Int32.MaxValue
162         }
163 
164         internal IntPtr chn;
165         private uint sample_size;
166 
167         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_id(IntPtr chn)168         private static extern IntPtr iio_channel_get_id(IntPtr chn);
169 
170         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_name(IntPtr chn)171         private static extern IntPtr iio_channel_get_name(IntPtr chn);
172 
173         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_attrs_count(IntPtr chn)174         private static extern uint iio_channel_get_attrs_count(IntPtr chn);
175 
176         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_attr(IntPtr chn, uint index)177         private static extern IntPtr iio_channel_get_attr(IntPtr chn, uint index);
178 
179         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
180         [return: MarshalAs(UnmanagedType.I1)]
iio_channel_is_output(IntPtr chn)181         private static extern bool iio_channel_is_output(IntPtr chn);
182 
183         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
184         [return: MarshalAs(UnmanagedType.I1)]
iio_channel_is_scan_element(IntPtr chn)185         private static extern bool iio_channel_is_scan_element(IntPtr chn);
186 
187         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_enable(IntPtr chn)188         private static extern void iio_channel_enable(IntPtr chn);
189 
190         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_disable(IntPtr chn)191         private static extern void iio_channel_disable(IntPtr chn);
192 
193         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
194         [return: MarshalAs(UnmanagedType.I1)]
iio_channel_is_enabled(IntPtr chn)195         private static extern bool iio_channel_is_enabled(IntPtr chn);
196 
197         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_read_raw(IntPtr chn, IntPtr buf, IntPtr dst, uint len)198         private static extern uint iio_channel_read_raw(IntPtr chn, IntPtr buf, IntPtr dst, uint len);
199 
200         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_write_raw(IntPtr chn, IntPtr buf, IntPtr src, uint len)201         private static extern uint iio_channel_write_raw(IntPtr chn, IntPtr buf, IntPtr src, uint len);
202 
203         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_read(IntPtr chn, IntPtr buf, IntPtr dst, uint len)204         private static extern uint iio_channel_read(IntPtr chn, IntPtr buf, IntPtr dst, uint len);
205 
206         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_write(IntPtr chn, IntPtr buf, IntPtr src, uint len)207         private static extern uint iio_channel_write(IntPtr chn, IntPtr buf, IntPtr src, uint len);
208 
209         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_data_format(IntPtr chn)210         private static extern IntPtr iio_channel_get_data_format(IntPtr chn);
211 
212         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_index(IntPtr chn)213         private static extern int iio_channel_get_index(IntPtr chn);
214 
215         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_device(IntPtr chn)216         private static extern IntPtr iio_channel_get_device(IntPtr chn);
217 
218         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_context(IntPtr dev)219         private static extern IntPtr iio_device_get_context(IntPtr dev);
220 
221         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_modifier(IntPtr chn)222         private static extern int iio_channel_get_modifier(IntPtr chn);
223 
224         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_get_type(IntPtr chn)225         private static extern int iio_channel_get_type(IntPtr chn);
226 
227         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_find_attr(IntPtr chn, [In] string name)228         private static extern IntPtr iio_channel_find_attr(IntPtr chn, [In] string name);
229 
230         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_convert(IntPtr chn, IntPtr dst, IntPtr src)231         private static extern void iio_channel_convert(IntPtr chn, IntPtr dst, IntPtr src);
232 
233         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_channel_convert_inverse(IntPtr chn, IntPtr dst, IntPtr src)234         private static extern void iio_channel_convert_inverse(IntPtr chn, IntPtr dst, IntPtr src);
235 
236         /// <summary>The name of this channel.</summary>
237         public readonly string name;
238 
239         /// <summary>An identifier of this channel.</summary>
240         /// <remarks>It is possible that two channels have the same ID,
241         /// if one is an input channel and the other is an output channel.</remarks>
242         public readonly string id;
243 
244         /// <summary>Contains <c>true</c> if the channel is an output channel,
245         /// <c>false</c> otherwise.</summary>
246         public readonly bool output;
247 
248         /// <summary>Contains <c>true</c> if the channel is a scan element,
249         /// <c>false</c> otherwise.</summary>
250         /// <remarks>If a channel is a scan element, then it is possible to enable it
251         /// and use it for I/O operations.</remarks>
252         public readonly bool scan_element;
253 
254         /// <summary>A <c>list</c> of all the attributes that this channel has.</summary>
255         public readonly List<Attr> attrs;
256 
257         /// <summary>The modifier of this channel.</summary>
258         public ChannelModifier modifier { get; private set; }
259 
260         /// <summary>The type of this channel.</summary>
261         public ChannelType type { get; private set; }
262 
Channel(IntPtr chn)263         internal Channel(IntPtr chn)
264         {
265             this.chn = chn;
266             attrs = new List<Attr>();
267             sample_size = (uint)Marshal.ReadInt32(iio_channel_get_data_format(this.chn)) / 8;
268             modifier = (ChannelModifier) iio_channel_get_modifier(chn);
269             type = (ChannelType) iio_channel_get_type(chn);
270             uint nb_attrs = iio_channel_get_attrs_count(chn);
271 
272             for (uint i = 0; i < nb_attrs; i++)
273             {
274                 attrs.Add(new ChannelAttr(this.chn, Marshal.PtrToStringAnsi(iio_channel_get_attr(chn, i))));
275             }
276 
277             IntPtr name_ptr = iio_channel_get_name(this.chn);
278             if (name_ptr == IntPtr.Zero)
279             {
280                 name = "";
281             }
282             else
283             {
284                 name = Marshal.PtrToStringAnsi(name_ptr);
285             }
286 
287             id = Marshal.PtrToStringAnsi(iio_channel_get_id(this.chn));
288             output = iio_channel_is_output(this.chn);
289             scan_element = iio_channel_is_scan_element(this.chn);
290         }
291 
292         /// <summary>Enable the current channel, so that it can be used for I/O operations.</summary>
enable()293         public void enable()
294         {
295             iio_channel_enable(this.chn);
296         }
297 
298         /// <summary>Disable the current channel.</summary>
disable()299         public void disable()
300         {
301             iio_channel_disable(this.chn);
302         }
303 
304         /// <summary>Returns whether or not the channel has been enabled.</summary>
is_enabled()305         public bool is_enabled()
306         {
307             return iio_channel_is_enabled(this.chn);
308         }
309 
310         /// <summary>Extract the samples corresponding to this channel from the
311         /// given <see cref="iio.IOBuffer"/> object.</summary>
312         /// <param name="buffer">A valid instance of the <see cref="iio.IOBuffer"/> class.</param>
313         /// <param name="raw">If set to <c>true</c>, the samples are not converted from their
314         /// hardware format to their host format.</param>
315         /// <returns>A <c>byte</c> array containing the extracted samples.</returns>
316         /// <exception cref="System.Exception">The samples could not be read.</exception>
read(IOBuffer buffer, bool raw = false)317         public byte[] read(IOBuffer buffer, bool raw = false)
318         {
319             if (!is_enabled())
320             {
321                 throw new Exception("Channel must be enabled before the IOBuffer is instantiated");
322             }
323             if (this.output)
324             {
325                 throw new Exception("Unable to read from output channel");
326             }
327 
328             byte[] array = new byte[(int) (buffer.samples_count * sample_size)];
329             MemoryStream stream = new MemoryStream(array, true);
330             GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
331             IntPtr addr = handle.AddrOfPinnedObject();
332             uint count;
333 
334             if (raw)
335             {
336                 count = iio_channel_read_raw(this.chn, buffer.buf, addr, buffer.samples_count * sample_size);
337             }
338             else
339             {
340                 count = iio_channel_read(this.chn, buffer.buf, addr, buffer.samples_count * sample_size);
341             }
342             handle.Free();
343             stream.SetLength((long) count);
344             return stream.ToArray();
345 
346         }
347 
348         /// <summary>
349         /// Write the specified array of samples corresponding to this channel into the
350         /// given <see cref="iio.IOBuffer"/> object.</summary>
351         /// <param name="buffer">A valid instance of the <see cref="iio.IOBuffer"/> class.</param>
352         /// <param name="array">A <c>byte</c> array containing the samples to write.</param>
353         /// <param name="raw">If set to <c>true</c>, the samples are not converted from their
354         /// host format to their native format.</param>
355         /// <returns>The number of bytes written.</returns>
356         /// <exception cref="System.Exception">The samples could not be written.</exception>
write(IOBuffer buffer, byte[] array, bool raw = false)357         public uint write(IOBuffer buffer, byte[] array, bool raw = false)
358         {
359             if (!is_enabled())
360             {
361                 throw new Exception("Channel must be enabled before the IOBuffer is instantiated");
362             }
363             if (!this.output)
364             {
365                 throw new Exception("Unable to write to an input channel");
366             }
367 
368             GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
369             IntPtr addr = handle.AddrOfPinnedObject();
370             uint count;
371 
372             if (raw)
373             {
374                 count = iio_channel_write_raw(this.chn, buffer.buf, addr, (uint) array.Length);
375             }
376             else
377             {
378                 count = iio_channel_write(this.chn, buffer.buf, addr, (uint) array.Length);
379             }
380             handle.Free();
381 
382             return count;
383         }
384 
385         /// <summary>Get the index of this channel.</summary>
get_index()386         public long get_index()
387         {
388             return iio_channel_get_index(chn);
389         }
390 
391         /// <summary>Finds the attribute of the current channel with the given name.</summary>
392         /// <returns><see cref="iio.Channel.ChannelAttr"/></returns>
393         /// <exception cref="System.Exception">There is no attribute with the given name.</exception>
find_attribute(string attribute)394         public Attr find_attribute(string attribute)
395         {
396             IntPtr attr = iio_channel_find_attr(chn, attribute);
397 
398             if (attr == IntPtr.Zero)
399             {
400                 throw new Exception("There is no attribute with the given name!");
401             }
402 
403             return new ChannelAttr(chn, Marshal.PtrToStringAnsi(attr));
404         }
405 
406         /// <summary>Finds the device of the current channel.</summary>
407         /// <returns><see cref="iio.Device"/></returns>
get_device()408         public Device get_device()
409         {
410             IntPtr dev_ptr = iio_channel_get_device(chn);
411             return new Device(new Context(dev_ptr), dev_ptr);
412         }
413 
414         /// <summary>Converts the data from the hardware format to the format of the arhitecture on which libiio is running.</summary>
convert(IntPtr dst, IntPtr src)415         public void convert(IntPtr dst, IntPtr src)
416         {
417             iio_channel_convert(chn, dst, src);
418         }
419 
420         /// <summary>Converts the data from the arhitecture on which libiio is running to the hardware format.</summary>
convert_inverse(IntPtr dst, IntPtr src)421         public void convert_inverse(IntPtr dst, IntPtr src)
422         {
423             iio_channel_convert_inverse(chn, dst, src);
424         }
425     }
426 }
427