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.Runtime.Remoting.Contexts;
24 using System.Security.Authentication.ExtendedProtection;
25 using System.Text;
26 using System.Threading.Tasks;
27 
28 namespace iio
29 {
30     /// <summary><see cref="iio.IOBuffer"/> class:
31     /// The class used for all I/O operations.</summary>
32     public class IOBuffer : IDisposable
33     {
34         private bool circular_buffer_pushed;
35 
36         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_create_buffer(IntPtr dev, uint samples_count, [MarshalAs(UnmanagedType.I1)] bool circular)37         private static extern IntPtr iio_device_create_buffer(IntPtr dev, uint samples_count,
38                                   [MarshalAs(UnmanagedType.I1)] bool circular);
39 
40         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_destroy(IntPtr buf)41         private static extern void iio_buffer_destroy(IntPtr buf);
42 
43         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_refill(IntPtr buf)44         private static extern int iio_buffer_refill(IntPtr buf);
45 
46         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_push_partial(IntPtr buf, uint samples_count)47         private static extern int iio_buffer_push_partial(IntPtr buf, uint samples_count);
48 
49         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_start(IntPtr buf)50         private static extern IntPtr iio_buffer_start(IntPtr buf);
51 
52         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_end(IntPtr buf)53         private static extern IntPtr iio_buffer_end(IntPtr buf);
54 
55         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_get_poll_fd(IntPtr buf)56         private static extern int iio_buffer_get_poll_fd(IntPtr buf);
57 
58         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_set_blocking_mode(IntPtr buf, bool blocking)59         private static extern int iio_buffer_set_blocking_mode(IntPtr buf, bool blocking);
60 
61         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_cancel(IntPtr buf)62         private static extern void iio_buffer_cancel(IntPtr buf);
63 
64         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_first(IntPtr buf, IntPtr chn)65         private static extern IntPtr iio_buffer_first(IntPtr buf, IntPtr chn);
66 
67         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_step(IntPtr buf)68         private static extern long iio_buffer_step(IntPtr buf);
69 
70         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_device_get_context(IntPtr dev)71         private static extern IntPtr iio_device_get_context(IntPtr dev);
72 
73         [DllImport("libiio.dll", CallingConvention = CallingConvention.Cdecl)]
iio_buffer_get_device(IntPtr buf)74         private static extern IntPtr iio_buffer_get_device(IntPtr buf);
75 
76         internal IntPtr buf;
77 
78         /// <summary>The size of this buffer, in samples.</summary>
79         public readonly uint samples_count;
80 
81         /// <summary>If <c>true</c>, the buffer is circular.</summary>
82         public readonly bool circular;
83 
84         /// <summary>Initializes a new instance of the <see cref="iio.IOBuffer"/> class.</summary>
85         /// <param name="dev">The <see cref="iio.Device"/> object that represents the device
86         /// where the I/O operations will be performed.</param>
87         /// <param name="samples_count">The size of the buffer, in samples.</param>
88         /// <param name="circular">If set to <c>true</c>, the buffer is circular.</param>
89         /// <exception cref="System.Exception">The buffer could not be created.</exception>
IOBuffer(Device dev, uint samples_count, bool circular = false)90         public IOBuffer(Device dev, uint samples_count, bool circular = false)
91         {
92             this.samples_count = samples_count;
93             this.circular = circular;
94             this.circular_buffer_pushed = false;
95 
96             buf = iio_device_create_buffer(dev.dev, samples_count, circular);
97             if (buf == IntPtr.Zero)
98             {
99                 throw new Exception("Unable to create buffer");
100             }
101         }
102 
~IOBuffer()103         ~IOBuffer()
104         {
105             if (buf != IntPtr.Zero)
106             {
107                 Dispose(false);
108             }
109         }
110 
111         /// <summary>Fetch a new set of samples from the hardware.</summary>
112         /// <exception cref="System.Exception">The buffer could not be refilled.</exception>
refill()113         public void refill()
114         {
115             int err = iio_buffer_refill(this.buf);
116             if (err < 0)
117             {
118                 throw new Exception("Unable to refill buffer: err=" + err);
119             }
120         }
121 
122         /// <summary>Submit the samples contained in this buffer to the hardware.</summary>
123         /// <exception cref="System.Exception">The buffer could not be pushed.</exception>
push(uint samples_count)124         public void push(uint samples_count)
125         {
126             if (circular && circular_buffer_pushed)
127             {
128                 throw new Exception("Circular buffer already pushed\n");
129             }
130 
131             int err = iio_buffer_push_partial(this.buf, samples_count);
132             if (err < 0)
133             {
134                 throw new Exception("Unable to push buffer: err=" + err);
135             }
136             circular_buffer_pushed = true;
137         }
138 
139         /// <summary>Submit all the samples contained in this buffer to the hardware.</summary>
push()140         public void push()
141         {
142             push(this.samples_count);
143         }
144 
145         /// <summary>Releases all resource used by the <see cref="iio.IOBuffer"/> object.</summary>
146         /// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="iio.IOBuffer"/>. The
147         /// <see cref="Dispose"/> method leaves the <see cref="iio.IOBuffer"/> in an unusable state. After calling
148         /// <see cref="Dispose"/>, you must release all references to the <see cref="iio.IOBuffer"/> so the garbage
149         /// collector can reclaim the memory that the <see cref="iio.IOBuffer"/> was occupying.</remarks>
Dispose()150         public void Dispose()
151         {
152             Dispose(true);
153         }
154 
Dispose(bool clean)155         private void Dispose(bool clean)
156         {
157             if (buf != IntPtr.Zero)
158             {
159                 if (clean)
160                 {
161                     GC.SuppressFinalize(this);
162                 }
163                 iio_buffer_destroy(buf);
164                 buf = IntPtr.Zero;
165             }
166         }
167 
168         /// <summary>Copy the given array of samples inside the <see cref="iio.IOBuffer"/> object.</summary>
169         /// <param name="array">A <c>byte</c> array containing the samples that should be written.</param>
170         /// <remarks>The number of samples written will not exceed the size of the buffer.</remarks>
fill(byte[] array)171         public void fill(byte[] array)
172         {
173             long length = (long) iio_buffer_end(buf) - (long) iio_buffer_start(buf);
174             if (length > array.Length)
175             {
176                 length = array.Length;
177             }
178             Marshal.Copy(array, 0, iio_buffer_start(buf), (int)length);
179         }
180 
181         /// <summary>Extract the samples from the <see cref="iio.IOBuffer"/> object.</summary>
182         /// <param name="array">A <c>byte</c> array containing the extracted samples.</param>
read(byte[] array)183         public void read(byte[] array)
184         {
185             long length = (long) iio_buffer_end(buf) - (long) iio_buffer_start(buf);
186             if (length > array.Length)
187             {
188                 length = array.Length;
189             }
190             Marshal.Copy(iio_buffer_start(buf), array, 0, (int)length);
191         }
192 
193         /// <summary>Returns poll file descriptor for the current buffer.</summary>
get_poll_fd()194         public int get_poll_fd()
195         {
196             return iio_buffer_get_poll_fd(buf);
197         }
198 
199         /// <summary>Sets the blocking behavior of the current buffer.</summary>
200         /// <param name="blocking">true if blocking buffer, otherwise false</param>
set_blocking_mode(bool blocking)201         public int set_blocking_mode(bool blocking)
202         {
203             return iio_buffer_set_blocking_mode(buf, blocking);
204         }
205 
206         /// <summary>Cancels the current buffer.</summary>
cancel()207         public void cancel()
208         {
209             iio_buffer_cancel(buf);
210         }
211 
212         /// <summary>Gets the device of the current buffer.</summary>
213         /// <returns>The device of the current buffer.</returns>
get_device()214         public Device get_device()
215         {
216             IntPtr dev = iio_buffer_get_device(buf);
217             return new Device(new Context(iio_device_get_context(dev)), dev);
218         }
219 
220         /// <summary>Gets a pointer to the first sample from the current buffer for a specific channel.</summary>
221         /// <param name="ch">The channel for which to find the first sample.</param>
first(Channel ch)222         public IntPtr first(Channel ch)
223         {
224             if (ch == null)
225             {
226                 throw new System.Exception("The channel should not be null!");
227             }
228             return iio_buffer_first(buf, ch.chn);
229         }
230 
231         /// <summary>Gets the step size of the current buffer.</summary>
step()232         public long step()
233         {
234             return iio_buffer_step(buf);
235         }
236     }
237 }
238