• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1% Copyright 2014(c) Analog Devices, Inc.
2%
3%  All rights reserved.
4%
5%  Redistribution and use in source and binary forms, with or without modification,
6%  are permitted provided that the following conditions are met:
7%      - Redistributions of source code must retain the above copyright
8%        notice, this list of conditions and the following disclaimer.
9%      - Redistributions in binary form must reproduce the above copyright
10%        notice, this list of conditions and the following disclaimer in
11%        the documentation and/or other materials provided with the
12%        distribution.
13%      - Neither the name of Analog Devices, Inc. nor the names of its
14%        contributors may be used to endorse or promote products derived
15%        from this software without specific prior written permission.
16%      - The use of this software may or may not infringe the patent rights
17%        of one or more patent holders.  This license does not release you
18%        from the requirement that you obtain separate licenses from these
19%        patent holders to use this software.
20%      - Use of the software either in source or binary form or filter designs
21%        resulting from the use of this software, must be connected to, run
22%        on or loaded to an Analog Devices Inc. component.
23%
24%  THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25%  INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
26%  PARTICULAR PURPOSE ARE DISCLAIMED.
27%
28%  IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29%  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY
30%  RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31%  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32%  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
33%  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35classdef libiio_if < handle
36    % libiio_if Interface object for for IIO devices
37
38    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39    %% Protected properties
40    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41    properties (Access = protected)
42        libname         = 'libiio';
43        hname           = 'iio.h';
44        dev_name        = '';
45        data_ch_no      = 0;
46        data_ch_size    = 0;
47        dev_type        = '';
48        iio_ctx         = {};
49        iio_dev         = {};
50        iio_buffer      = {};
51        iio_channel     = {};
52        iio_buf_size    = 8192;
53        iio_scan_elm_no = 0;
54        if_initialized  = 0;
55    end
56
57    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58    %% Static private methods
59    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60    methods (Static, Access = private)
61        function out = modInstanceCnt(val)
62            % Manages the number of object instances to handle proper DLL unloading
63            persistent instance_cnt;
64            if isempty(instance_cnt)
65                instance_cnt = 0;
66            end
67            instance_cnt = instance_cnt + val;
68            out = instance_cnt;
69        end
70    end
71
72    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73    %% Protected methods
74    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75    methods (Access = protected)
76        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77        %% Creates the network context
78        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79        function [ret, err_msg, msg_log] = createNetworkContext(obj, ip_address)
80            % Initialize the return values
81            ret = -1;
82            err_msg = '';
83            msg_log = [];
84
85            % Create the network context
86            obj.iio_ctx = calllib(obj.libname, 'iio_create_network_context', ip_address);
87
88            % Check if the network context is valid
89            if (isNull(obj.iio_ctx))
90                obj.iio_ctx = {};
91                err_msg = 'Could not connect to the IIO server!';
92                return;
93            end
94
95            % Increase the object's instance count
96            libiio_if.modInstanceCnt(1);
97            msg_log = [msg_log sprintf('%s: Connected to IP %s\n', class(obj), ip_address)];
98
99            % Set the return code to success
100            ret = 0;
101        end
102
103        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104        %% Releases the network context and unload the libiio library
105        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106        function releaseContext(obj)
107            calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx);
108            obj.iio_ctx = {};
109            instCnt = libiio_if.modInstanceCnt(-1);
110            if(instCnt == 0)
111                unloadlibrary(obj.libname);
112            end
113        end
114
115        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116        %% Checks the compatibility of the different software modules.
117        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118        function [ret, err_msg, msg_log] = checkVersions(obj)
119            % Initialize the return values
120            ret = -1;
121            err_msg = '';
122            msg_log = [];
123
124            % Create a set of pointers to read the iiod and dll versions
125            data = zeros(1, 10);
126            remote_pMajor = libpointer('uint32Ptr', data(1));
127            remote_pMinor = libpointer('uint32Ptr', data(2));
128            remote_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]);
129            local_pMajor = libpointer('uint32Ptr', data(1));
130            local_pMinor = libpointer('uint32Ptr', data(2));
131            local_pGitTag = libpointer('int8Ptr', [int8(data(3:end)) 0]);
132
133            % get remote libiio version
134            calllib(obj.libname, 'iio_context_get_version', obj.iio_ctx, remote_pMajor, remote_pMinor, remote_pGitTag);
135            % extract git hash without trailing null char
136            remote_githash = remote_pGitTag.Value(1:7);
137            remote_version_str = sprintf('Remote libiio version: %d.%d, (git-%s)', remote_pMajor.Value, remote_pMinor.Value, remote_githash);
138            msg_log = [msg_log sprintf('%s: %s\n', class(obj), remote_version_str)];
139
140            % get local libiio version
141            calllib(obj.libname, 'iio_library_get_version', local_pMajor, local_pMinor, local_pGitTag);
142            local_githash = local_pGitTag.Value(1:7);
143            local_version_str = sprintf('Local libiio version: %d.%d, (git-%s)', local_pMajor.Value, local_pMinor.Value, local_githash);
144            msg_log = [msg_log sprintf('%s: %s\n', class(obj), local_version_str)];
145
146            if(remote_pMajor.Value < local_pMajor.Value)
147                err_msg = ['The libiio version running on the device is outdated! ' ...
148                    'Run the adi_update_tools.sh script to get libiio up to date.'];
149                return;
150            elseif(remote_pMajor.Value > local_pMajor.Value)
151                err_msg = ['The libiio version on the local host is outdated! ' ...
152                    'On Windows, reinstall the dll using the latest installer ' ...
153                    'from the Analog Devices wiki.'];
154                return;
155            end
156
157            % Set the return code to success
158            ret = 0;
159        end
160
161        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162        %% Detect if the specified device is present in the system
163        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164        function [ret, err_msg, msg_log] = initDevice(obj, dev_name)
165            % Initialize the return values
166            ret = -1;
167            err_msg = '';
168            msg_log = [];
169
170            % Store the device name
171            obj.dev_name = dev_name;
172
173            % Get the number of devices
174            nb_devices = calllib(obj.libname, 'iio_context_get_devices_count', obj.iio_ctx);
175
176            % If no devices are present return with error
177            if(nb_devices == 0)
178                err_msg = 'No devices were detected in the system!';
179                return;
180            end
181            msg_log = [msg_log sprintf('%s: Found %d devices in the system\n', class(obj), nb_devices)];
182
183            % Detect if the targeted device is installed
184            dev_found = 0;
185            for i = 0 : nb_devices - 1
186                dev = calllib(obj.libname, 'iio_context_get_device', obj.iio_ctx, i);
187                name = calllib(obj.libname, 'iio_device_get_name', dev);
188                if(strcmp(name, dev_name))
189                    obj.iio_dev = dev;
190                    dev_found = 1;
191                    break;
192                end
193                clear dev;
194            end
195
196            % Check if the target device was detected
197            if(dev_found == 0)
198                err_msg = 'Could not find target configuration device!';
199                return;
200            end
201
202            msg_log = [msg_log sprintf('%s: %s was found in the system\n', class(obj), obj.dev_name)];
203
204            % Set the return code to success
205            ret = 0;
206        end
207
208        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209        %% Initializes the output data channels
210        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
211        function [ret, err_msg, msg_log] = initOutputDataChannels(obj, ch_no, ch_size)
212            % Initialize the return values
213            ret = -1;
214            err_msg = '';
215            msg_log = [];
216
217            % Save the number of channels and size
218            obj.data_ch_no = ch_no;
219            obj.data_ch_size = ch_size;
220
221            % Get the number of channels that the device has
222            nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev);
223            if(nb_channels == 0)
224                err_msg = 'The selected device does not have any channels!';
225                return;
226            end
227
228            % Enable the data channels
229            if(ch_no ~= 0)
230                % Check if the device has output channels. The
231                % logic here assumes that a device can have
232                % only input or only output channels
233                obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0);
234                is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1});
235                if(is_output == 0)
236                    err_msg = 'The selected device does not have output channels!';
237                    return;
238                end
239                % Enable all the channels
240                for j = 0 : nb_channels - 1
241                    obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j);
242                    if(j < ch_no)
243                        calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1});
244                        is_scan_element = calllib(obj.libname, 'iio_channel_is_scan_element', obj.iio_channel{j+1});
245                        if(is_scan_element == 1)
246                            obj.iio_scan_elm_no = obj.iio_scan_elm_no + 1;
247                        end
248                    else
249                        calllib(obj.libname, 'iio_channel_disable', obj.iio_channel{j+1});
250                    end
251                end
252                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)];
253
254                % Check if the number of channels in the device
255                % is greater or equal to the system object
256                % input channels
257                if(obj.iio_scan_elm_no < ch_no)
258                    obj.iio_channel = {};
259                    err_msg = 'The selected device does not have enough output channels!';
260                    return;
261                end
262
263                % Enable the DAC buffer output
264                obj.if_initialized = 1;
265                ret = writeAttributeString(obj, 'altvoltage0*raw', '0');
266                obj.if_initialized = 0;
267                if(ret < 0)
268                    obj.iio_channel = {};
269                    err_msg = 'Could not enable the DAC buffer output!';
270                    return;
271                end
272
273                % Create the IIO buffer used to write data
274                obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no;
275                obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,...
276                                         obj.data_ch_size, 1);
277            end
278
279            msg_log = [msg_log sprintf('%s: %s output data channels successfully initialized\n', class(obj), obj.dev_name)];
280
281            % Set the return code to success
282            ret = 0;
283        end
284
285        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286        %% Initializes the input data channels
287        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288        function [ret, err_msg, msg_log] = initInputDataChannels(obj, ch_no, ch_size)
289            % Initialize the return values
290            ret = -1;
291            err_msg = '';
292            msg_log = [];
293
294            % Save the number of channels and size
295            obj.data_ch_no = ch_no;
296            obj.data_ch_size = ch_size;
297
298            % Get the number of channels that the device has
299            nb_channels = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev);
300            if(nb_channels == 0)
301                err_msg = 'The selected device does not have any channels!';
302                return;
303            end
304
305            % Enable the system object output channels
306            if(ch_no ~= 0)
307                % Check if the device has input channels. The
308                % logic here assumes that a device can have
309                % only input or only output channels
310                obj.iio_channel{1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, 0);
311                is_output = calllib(obj.libname, 'iio_channel_is_output', obj.iio_channel{1});
312                if(is_output == 1)
313                    err_msg = 'The selected device does not have input channels!';
314                    return;
315                end
316                msg_log = [msg_log sprintf('%s: Found %d input channels for the device %s\n', class(obj), nb_channels, obj.dev_name)];
317
318                % Check if the number of channels in the device
319                % is greater or equal to the system object
320                % output channels
321                if(nb_channels < ch_no)
322                    obj.iio_channel = {};
323                    err_msg = 'The selected device does not have enough input channels!';
324                    return;
325                end
326
327                % Enable the channels
328                for j = 0 : ch_no - 1
329                    obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j);
330                    calllib(obj.libname, 'iio_channel_enable', obj.iio_channel{j+1});
331                end
332                for j = ch_no : nb_channels - 1
333                    obj.iio_channel{j+1} = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, j);
334                    calllib(obj.libname, 'iio_channel_disable', obj.iio_channel{j+1});
335                end
336                % Create the IIO buffer used to read data
337                obj.iio_buf_size = obj.data_ch_size * obj.data_ch_no;
338                obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev, obj.iio_buf_size, 0);
339            end
340
341            msg_log = [msg_log sprintf('%s: %s input data channels successfully initialized\n', class(obj), obj.dev_name)];
342
343            % Set the return code to success
344            ret = 0;
345        end
346
347    end
348
349
350    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351    %% Public methods
352    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353    methods
354        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355        %% Constructor
356        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357        function obj = libiio_if()
358            % Constructor
359            obj.if_initialized = 0;
360        end
361
362        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363        %% Destructor
364        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365        function delete(obj)
366            % Release any resources used by the system object.
367            if((obj.if_initialized == 1) && libisloaded(obj.libname))
368                if(~isempty(obj.iio_buffer))
369                    calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer);
370                end
371                if(~isempty(obj.iio_ctx))
372                    calllib(obj.libname, 'iio_context_destroy', obj.iio_ctx);
373                end
374                obj.iio_buffer = {};
375                obj.iio_channel = {};
376                obj.iio_dev = {};
377                obj.iio_ctx = {};
378                instCnt = libiio_if.modInstanceCnt(-1);
379                if(instCnt == 0)
380                    unloadlibrary(obj.libname);
381                end
382            end
383        end
384
385        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386        %% Initializes the libiio interface
387        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388        function [ret, err_msg, msg_log] = init(obj, ip_address, ...
389                                                dev_name, dev_type, ...
390                                                data_ch_no, data_ch_size)
391            % Initialize the return values
392            ret = -1;
393            err_msg = '';
394            msg_log = [];
395
396            % Save the device type
397            obj.dev_type = dev_type;
398
399            % Set the initialization status to fail
400            obj.if_initialized = 0;
401
402            % Load the libiio library
403            if(~libisloaded(obj.libname))
404                try
405                    [notfound, warnings] = loadlibrary(obj.libname, obj.hname);
406                catch exception
407                    err_msg = exception.message;
408                    return;
409                end
410            end
411
412            if(~libisloaded(obj.libname))
413                err_msg = 'Could not load the libiio library!';
414                return;
415            end
416
417            % Create the network context
418            [ret, err_msg, msg_log] = createNetworkContext(obj, ip_address);
419            if(ret < 0)
420                return;
421            end
422
423            % Check the software versions
424            [ret, err_msg, msg_log_new] = checkVersions(obj);
425            msg_log = [msg_log msg_log_new];
426            if(ret < 0)
427                releaseContext(obj);
428                return;
429            end
430
431            % Initialize the device
432            [ret, err_msg, msg_log_new] = initDevice(obj, dev_name);
433            msg_log = [msg_log msg_log_new];
434            if(ret < 0)
435                releaseContext(obj);
436                return;
437            end
438
439            % Initialize the output data channels
440            if(strcmp(dev_type, 'OUT'))
441                [ret, err_msg, msg_log_new] = initOutputDataChannels(obj, data_ch_no, data_ch_size);
442                msg_log = [msg_log msg_log_new];
443                if(ret < 0)
444                    releaseContext(obj);
445                    return;
446                end
447            end
448
449            % Initialize the input data channels
450            if(strcmp(dev_type, 'IN'))
451                [ret, err_msg, msg_log_new] = initInputDataChannels(obj, data_ch_no, data_ch_size);
452                msg_log = [msg_log msg_log_new];
453                if(ret < 0)
454                    releaseContext(obj);
455                    return;
456                end
457            end
458
459            % Set the initialization status to success
460            obj.if_initialized = 1;
461        end
462
463        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464        %% Implement the data capture flow
465        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466        function [ret, data] = readData(obj)
467            % Initialize the return values
468            ret = -1;
469            data = cell(1, obj.data_ch_no);
470            for i = 1 : obj.data_ch_no
471                data{i} = zeros(obj.data_ch_size, 1);
472            end
473
474            % Check if the interface is initialized
475            if(obj.if_initialized == 0)
476                return;
477            end
478
479            % Check if the device type is output
480            if(~strcmp(obj.dev_type, 'IN'))
481                return;
482            end
483
484            % Read the data
485            calllib(obj.libname, 'iio_buffer_refill', obj.iio_buffer);
486            buffer = calllib(obj.libname, 'iio_buffer_first', obj.iio_buffer, obj.iio_channel{1});
487            setdatatype(buffer, 'int16Ptr', obj.iio_buf_size);
488            for i = 1 : obj.data_ch_no
489                data{i} = double(buffer.Value(i:obj.data_ch_no:end));
490            end
491
492            % Set the return code to success
493            ret = 0;
494        end
495
496        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497        %% Implement the data transmit flow
498        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499        function ret = writeData(obj, data)
500            % Initialize the return values
501            ret = -1;
502
503            % Check if the interface is initialized
504            if(obj.if_initialized == 0)
505                return;
506            end
507
508            % Check if the device type is input
509            if(~strcmp(obj.dev_type, 'OUT'))
510                return;
511            end
512
513            % Destroy the buffer
514            calllib(obj.libname, 'iio_buffer_destroy', obj.iio_buffer);
515            obj.iio_buffer = {};
516
517            % Enable the DAC buffer output
518            ret = writeAttributeString(obj, 'altvoltage0*raw', '0');
519            if(ret < 0)
520                obj.iio_channel = {};
521                err_msg = 'Could not enable the DAC buffer output!';
522                return;
523            end
524
525            % Create the IIO buffer used to write data
526            obj.iio_buf_size = obj.data_ch_size * obj.iio_scan_elm_no;
527            obj.iio_buffer = calllib(obj.libname, 'iio_device_create_buffer', obj.iio_dev,...
528                                     obj.data_ch_size, 1);
529
530            % Transmit the data
531            buffer = calllib(obj.libname, 'iio_buffer_start', obj.iio_buffer);
532            setdatatype(buffer, 'int16Ptr', obj.iio_buf_size);
533            for i = 1 : obj.data_ch_no
534                buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = int16(data{i});
535            end
536            for i = obj.data_ch_no + 1 : obj.iio_scan_elm_no
537                buffer.Value(i : obj.iio_scan_elm_no : obj.iio_buf_size) = 0;
538            end
539            calllib(obj.libname, 'iio_buffer_push', obj.iio_buffer);
540
541            % Set the return code to success
542            ret = 0;
543        end
544
545        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546        %% Find an attribute based on the name. The name can contain wildcard '*' characters
547        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
548        function [ret, ch, attr] = findAttribute(obj, attr_name)
549            % Initialize the return values
550            ret = -1;
551            ch = 0;
552            attr = '';
553
554            % Check if the interface is initialized
555            if(obj.if_initialized == 0)
556                return;
557            end
558
559            % Check if this is a device attribute
560            name = calllib(obj.libname, 'iio_device_find_attr', obj.iio_dev, attr_name);
561            if(~isempty(name))
562                ret = 0;
563                return;
564            end
565
566            % This is a channel attribute, search for the corresponding channel
567            chn_no = calllib(obj.libname, 'iio_device_get_channels_count', obj.iio_dev);
568            for k = 0 : chn_no - 1
569                ch = calllib(obj.libname, 'iio_device_get_channel', obj.iio_dev, k);
570                attr_no = calllib(obj.libname, 'iio_channel_get_attrs_count', ch);
571                attr_found = 0;
572                for l = 0 : attr_no - 1
573                    attr = calllib(obj.libname, 'iio_channel_get_attr', ch, l);
574                    name = calllib(obj.libname, 'iio_channel_attr_get_filename', ch, attr);
575                    % The attribute to find can contain wildcard '*' characters,
576                    % search for all the substrings in the attribute name
577                    str_find = strsplit(attr_name, '*');
578                    str_find = str_find(find(~strcmp(str_find, '')));
579                    has_wildcard = ~isempty(strfind(attr_name, '*'));
580                    attr_found = 1;
581                    for i = 1 : length(str_find)
582                        if(has_wildcard == 0)
583                            ret = strcmp(name, str_find{i});
584                            if(ret == 0)
585                                ret = [];
586                            end
587                        else
588                            ret = strfind(name, str_find{i});
589                        end
590                        if(isempty(ret))
591                            attr_found = 0;
592                            break;
593                        end
594                    end
595                    if(attr_found == 1)
596                        break;
597                    end
598                    clear attr;
599                end
600                % Check if the attribute was found
601                if(attr_found == 0)
602                    clear ch;
603                else
604                    ret = 1;
605                    break;
606                end
607            end
608        end
609
610        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
611        %% Read an attribute as a double value
612        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
613        function [ret, val] = readAttributeDouble(obj, attr_name)
614            % Find the attribute
615            [ret, ch, attr] = findAttribute(obj, attr_name);
616            if(ret < 0)
617                val = 0;
618                return;
619            end
620
621            % Create a double pointer to be used for data read
622            data = zeros(1, 10);
623            pData = libpointer('doublePtr', data(1));
624
625            % Read the attribute value
626            if(ret > 0)
627                calllib(obj.libname, 'iio_channel_attr_read_double', ch, attr, pData);
628                clear ch;
629                clear attr;
630            else
631                calllib(obj.libname, 'iio_device_attr_read_double', obj.iio_dev, attr_name, pData);
632            end
633            val = pData.Value;
634        end
635
636        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637        %% Read an attribute as a string value
638        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639        function [ret, val] = readAttributeString(obj, attr_name)
640            % Find the attribute
641            [ret, ch, attr] = findAttribute(obj, attr_name);
642            if(ret < 0)
643                val = '';
644                return;
645            end
646
647            % Create a pointer to be used for data read
648            data = char(ones(1, 512));
649            pData = libpointer('stringPtr', data);
650
651            % Read the attribute value
652            if(ret > 0)
653                [~, ~, ~, val] = calllib(obj.libname, 'iio_channel_attr_read', ch, attr, pData, 512);
654                clear ch;
655                clear attr;
656            else
657                [~, ~, ~, val] = calllib(obj.libname, 'iio_device_attr_read', obj.iio_dev, attr_name, pData, 512);
658            end
659        end
660
661        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662        %% Write a string double value
663        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664        function ret = writeAttributeDouble(obj, attr_name, val)
665            % Find the attribute
666            [ret, ch, attr] = findAttribute(obj, attr_name);
667            if(ret < 0)
668                return;
669            end
670
671            % Write the attribute
672            if(ret > 0)
673                calllib(obj.libname, 'iio_channel_attr_write_double', ch, attr, val);
674                clear ch;
675                clear attr;
676            else
677                calllib(obj.libname, 'iio_device_attr_write_double', obj.iio_dev, attr_name, val);
678            end
679        end
680
681        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
682        %% Write a string attribute value
683        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
684        function ret = writeAttributeString(obj, attr_name, str)
685            % Find the attribute
686            [ret, ch, attr] = findAttribute(obj, attr_name);
687            if(ret < 0)
688                return;
689            end
690
691            % Write the attribute
692            if(ret > 0)
693                calllib(obj.libname, 'iio_channel_attr_write', ch, attr, str);
694                clear ch;
695                clear attr;
696            else
697                calllib(obj.libname, 'iio_device_attr_write', obj.iio_dev, attr_name, str);
698            end
699        end
700    end
701end
702