Code covered by the BSD License  

Highlights from
MATLAB Support Package for Velleman K8055/VM110 Experiment Board

MATLAB Support Package for Velleman K8055/VM110 Experiment Board

by

 

MATLAB library for communicating with a Velleman K8055/VM110 USB Experiment Interface Board

vellboard.ExperimentBoard
classdef ExperimentBoard < handle
% ExperimentBoard: Wrapper class for accessing the Velleman K8055 USB
% Experiment Interface Board.
%
%   EB = vellboard.ExperimentBoard() creates an ExperimentBoard object that
%   will automatically connect to any attached K8055 devices. You can then
%   access all the board's functions by using EB.Method, where Method is
%   the method you'd like to access.
%
%   EB = vellboard.ExperimentBoard('test') creates an ExperimentBoard object
%   in test mode. This skips device connection so the class can be used
%   without a K8055 device. Note that calling getActiveDevices will connect
%   any attached devices, even in test mode.
%
%   ExperimentBoard objects can access up to four connected devices. Note
%   that a second instance of the ExperimentBoard class accesses the same
%   devices, and may cause interference with the other instances. 
%   Therefore, having two active instances of the class is not recommended.

%   MATLAB Support Package for Velleman K8055/VM110
%   Version 1.0
%   Copyright 2011 The MathWorks, Inc.
    
    %% properties
    
    properties (SetAccess = private)
        testmode % Shows whether ExperimentBoard object is in test mode
    end


    %% constructor
    methods
        function obj = ExperimentBoard(test)
            % ExperimentBoard.ExperimentBoard()
            %   Constructor class for vellboard.ExperimentBoard. Creates a
            %   vellboard.ExperimentBoard object that allows access to the K8055
            %   functionality. See class help for more help on object creation.
            
            if exist('test','var') && strcmp(test,'test')
                obj.testmode = 1;
            else
                obj.testmode = 0;
            end
            
            %Check that MATLAB is 32-bit Windows
            if ~strcmp(computer,'PCWIN')
                error('vellboard:VersionError',...
                    'This package is only compatible with 32-bit MATLAB on a Windows system')
            end
                
            %Attempt to load K8055 library
            pref = vellboard.Prefs;
            dllloc = pref.K8055_DLL_Location;
            
            if ~libisloaded('K8055D')
                if exist(dllloc,'file')
                    if exist([fileparts(mfilename('fullpath')) '\K8055D_h'],'file')
                        loadlibrary(dllloc,@vellboard.K8055D_h);
                    elseif exist('K8055D.h','file')
                        warning('vellboard:CHeader',...
                            'Using C header file to load K8055D.dll. Prototype file is faster!')
                        loadlibrary(dllloc,'K8055D.h')
                    else
                        error('vellboard:MissingHeader',...
                            'Could not find K8055D.h or K8055D_h.m header file')
                    end
                else
                    error('vellboard:MissingDLL','Could not find K8055D.dll.')
                end
            end
            
            
            %Grab DLL version and display (also indicates successful DLL
            %load)
            version = obj.version;    
            fprintf('\nDLL Version: %s\n',version);
            if ~strcmp(version,'4.0.0.0')
                warning('vellboard:DLLVersion',...
                    ['This code was designed for version 4.0.0.0 of the DLL. Other versions may' ...
                    'work but may be missing functionaility. If you encounter any errors,'...
                    'please contact classroom-resources@mathworks.com with details.']);
            end
            
              % Attempt to open connection to device
%             address = 0;
%             
%             if ~isempty(varargin) && ~isa(varargin(1),{'numeric'})
%                 address = varargin(1);
%             end
%             success = calllib('K8055D','OpenDevice',address);
%             
%             % If conncection attempt fails, close library and abort
%             if success == -1
%                 delete(obj);
%                 error('Could not establish connection to 8055')
%             end
          
            if ~obj.testmode
                try
                    %search for and establish connection to any K8055 devices
                    devices = obj.getActiveDevices();
                    if isempty(devices)
                        error('vellboard:NoDevices','No K8055 devices found');
                    end

                    fprintf('Connected device addresses:')
                    for i = 1:size(devices,2)
                        fprintf(' %u',devices(i))
                    end
                    fprintf('\n')
                    
                    
                    %set current device as one with smallest address (can be
                    %changed later)
                    
                    obj.setCurrentDevice(devices(1));
                    fprintf('Current device has address %u\n',devices(1))
                    
                catch exception
                    calllib('K8055D','CloseDevice');
                    unloadlibrary('K8055D');
                    rethrow(exception);
                end
            else
                fprintf('Running in test mode.\nSimulating four connected devices.\nInput will not affect attached devices.\n');
            end
        end
        
        %% destructor
        function delete(obj) %#ok<*MANU>
            % ExperimentBoard.delete()
            %   Destructor method for the vellboard.ExperimentBoard. Called upon object
            %   deletion. Disconnects any connected devices and unloads the K8055
            %   library. Typically called by calling delete(varname), where varname is
            %   the name of the ExperimentBoard object you want to delete.

            % Close device connection and unload library
            if libisloaded('K8055D') && ~obj.testmode
                calllib('K8055D','CloseDevice');
                unloadlibrary('K8055D');
                fprintf('\n8055 Experiment Board disconnected\n');
            elseif obj.testmode
                unloadlibrary('K8055D');
                fprintf('\nEnding test mode\n');
            end
        end
        
        %% Returns an array listing all currently connected devices by
        % address
        function result = getActiveDevices(obj) 
            % ExperimentBoard.getActiveDevices()
            %   Returns an array of the addresses of attached K8055 devices. Also
            %   connects any unconnected devices so they can be accessed. Note that
            %   this does not change the current device; use
            %   ExperimentBoard.setCurrentDevice instead.
            if(obj.testmode)
                result = [1 2 3 4];
            else
                searchresult = calllib('K8055D','SearchDevices');
                result = [];
                for i = 1:4
                    if bitget(searchresult,i)
                        result = [result,i-1]; %#ok<AGROW>
                    end
                end
            end
        end
            
        
        %% Sets the current device that all board-accessing functions use
        function setCurrentDevice(obj,boardaddress)
            % ExperimentBoard.setCurrentDevice(boardaddress)
            %   Sets the current device to the device with the address defined by
            %   boardaddress. Will throw an error if boardaddress is not the address of
            %   a currently connected device. Use ExperimentBoard.getActiveDevices to
            %   get a list of valid values for boardaddress.

            if nargin ~= 2
                error('vellboard:ImproperArguments',['Calling syntax: obj.setCurrentDevice(boardaddress)' char(10) ...
                    'Where boardaddress = the address of a connected card (0 <= boardaddress <= 3)'])
            end
            
            validateattributes(boardaddress,{'numeric'},{'scalar','integer','>=',0,'<=',3});
            
            if ~obj.testmode
                result = calllib('K8055D','SetCurrentDevice',boardaddress);
            else
                if any(boardaddress == [0 1 2 3])
                    result = 1;
                else
                    result = -1;
                end
            end
            
                
            if result == -1
                devices = obj.getActiveDevices();
                error('vellemen:InvalidDevice',['Specified device not connected.' ...
                    'Currently connected devices:' ...
                    num2str(devices)]);
            end
        end
            
        %% Reads the value of analog input "channel"
        function result = readAnalog(obj,channel)
            % result = ExperimentBoard.readAnalog(channel)
            %   Reads data from the analog input channel defined by channel. Returns a
            %   integer between 0 and 255 representing a voltage range of 0V to ~5V.

            if nargin ~= 2
                error('vellboard:ImproperArguments',['Calling syntax: obj.readAnalog(channel)' char(10) ...
                    'Where channel = analog channel to be read (1 <= channel <= 2)'])
            end
            
            validateattributes(channel,{'numeric'},{'scalar','integer','>=',1,'<=',2});
            
            if obj.testmode
                result = 0;
            else
                result = calllib('K8055D','ReadAnalogChannel',channel);
            end
        end
        
        %% Reads both analog input channels
        function result = readAnalogAll(obj)
            % result = ExperimentBoard.readAnalogAll()
            %   Reads data from both analog input channels at once. Returns a 1x2 vector
            %   containing integers from 0 to 255 representing a voltage range of 0V to
            %   ~5V. result(1) is the result from channel 1, and result(2) is the result
            %   from channel 2.

            data1 = libpointer('int32Ptr',0);
            data2 = libpointer('int32Ptr',0);
            
            if obj.testmode
                result = [0 0];
            else
                calllib('K8055D','ReadAllAnalog',data1,data2);
                result = [data1.value data2.value];
            end
        end
        
        %% Outputs value of "data" to analog output "channel"
        function writeAnalog(obj,channel,data)
            % ExperimentBoard.writeAnalog(channel,data)
            %   Outputs the value defined by data to the analog output channel defined
            %   by channel. Data must be a integer between 0 and 255, with 0 being 0V
            %   and 255 being ~5V.

            if nargin ~= 3
                error('vellboard:ImproperArguments',['Calling syntax: obj.writeAnalog(channel,data)' char(10) ...
                    'Where channel = analog channel to be output to (1 <= channel <= 2)' char(10)...
                    'and data = data to be outputted (0 <= data <= 255)'])
            end
            
            validateattributes(channel,{'numeric'},{'scalar','integer','>=',1,'<=',2});
            validateattributes(data,{'numeric'},{'scalar','integer','>=',0,'<=',255});
            
            if ~obj.testmode
                calllib('K8055D','OutputAnalogChannel',channel,data);
            end
        end
        
        %% Outputs contents of "datavec" to both analog outputs
        function writeAnalogAll(obj,datavec)
            % ExperimentBoard.writeAnalogAll(datavec)
            %   Outputs to both analog outputs at once. datavec is a 1x2 vector
            %   containing two integers, both between 0 and 255. datavec(1) is the
            %   output to analog output channel 1, and datavec(2) is the output to
            %   analog output channel 2. For example, if datavec = [0 255], channel 1
            %   will be set to 0V and channel 2 will be set to ~5V.

            if nargin ~= 2
                error('vellboard:ImproperArguments',['Calling syntax: obj.writeAnalogAll(datavec)' char(10) ...
                    'Where datavec = 1x2 vector containing data to be output to each channel (0 <= data <= 255)']);
            end
            
            validateattributes(datavec,{'numeric'},{'size',[1 2],'integer','>=',0,'<=',255});
            
            if ~obj.testmode
                calllib('K8055D','OutputAllAnalog',datavec(1),datavec(2));
            end
        end
        
        %% Reads the value of digital input channel "channel"
        function result = readDigital(obj,channel)
            % result = ExperimentBoard.readDigital(channel)
            %   Reads data from the digital input defined by channel. Returns a 0 or 1
            %   for a low or high input, respectively.

            if nargin ~= 2
                error('vellboard:ImproperArguments',['Calling syntax: obj.readDigital(channel)' char(10) ...
                    'Where channel = digital channel to be read (1 <= channel <= 5)'])
            end
            
            validateattributes(channel,{'numeric'},{'scalar','integer','>=',1,'<=',5});
            
            if obj.testmode
                result = 0;
            else
                result = calllib('K8055D','ReadDigitalChannel',channel);
                result = cast(result,'int32'); %returns logical; int is handier
            end
        end 
        
        %% Reads the value of all digital inputs and returns 5-bit result 
        % as a binary vector
        function result = readDigitalAll(obj) 
            % result = ExperimentBoard.readDigitalAll()
            %   Reads data from all the digital inputs in one function call. Returns a
            %   1x5 binary vector with each entry containing a 1 or 0. Each entry
            %   corresponds with a digital input, with 1 being a high input and 0 being
            %   a low input. For example, if result(5) = 1, that means that digital
            %   input 5 is high.

            if obj.testmode
                result = [0 0 0 0 0];
            else
                result = vellboard.util.int2binvec(calllib('K8055D','ReadAllDigital'),5);
                result = cast(result,'int32'); %returns logical; int is handier.
            end
        end
        
        %% Writes value of data (1 bit) to digital output "channel"
        function writeDigital(obj,channel,data)
            % ExperimentBoard.writeDigital(channel,data)
            %   Writes the value of data to the digital output defined by channel. Data
            %   should be either a one or zero, with 1 = turn the channel on, and 0 =
            %   turn the channel off.

            if nargin ~= 3
                error('vellboard:ImproperArguments',['Calling syntax: obj.writeAnalog(channel,data)' char(10) ...
                    'Where channel = analog channel to be output to (1 <= channel <= 8)' char(10)...
                    'and data = data to be outputted (0 <= data <= 1)'])
            end
            
            validateattributes(channel,{'numeric'},{'scalar','integer','>=',1,'<=',8});
            validateattributes(data,{'numeric'},{'binary'});
            
            if ~obj.testmode
                if data
                    calllib('K8055D','SetDigitalChannel',channel);
                else
                    calllib('K8055D','ClearDigitalChannel',channel);
                end
            end
        end       
        
        
        %% Write 8-bit value to all digital outputs
        function writeDigitalAll(obj,datavec)
            % ExperimentBoard.writeDigitalAll(datavec)
            %   Sets the value of all the digital outputs in one function call. Each
            %   output is set based on the value of its corresponding entry in datavec,
            %   which is a 1x8 vector, with a one setting the channel high and a zero
            %   setting it low. For example, if datavec(1) is 1, channel 1 will be set
            %   high. Note that this means your binary vector will be written from left
            %   to right, ie. the binary vector of 110 will be [0 1 1]. You can use
            %   vellboard.util.dec2binvec to convert any integer number to a
            %   corresponding binary vector.

            if nargin ~= 2
                error('vellboard:ImproperArguments',['Calling syntax: obj.writeAllDigital(datavec)' char(10) ...
                    'Where data = 8-bit binary'])
            end
            
            validateattributes(datavec,{'numeric'},{'size',[1 8],'binary'});
            
            if ~obj.testmode;
                data = vellboard.util.binvec2int(datavec);            
                calllib('K8055D','WriteAllDigital',data);
            end
        end
        
        %% Reads the value of pulse counter #"counter"
        function result = readCounter(obj,counter)
            % result = ExperimentBoard.readCounter(counter)
            %   Reads the current value for the counter associated with the digital
            %   input defined by counter (only inputs 1 and 2 have counter
            %   functionality). The counter counts the number of times the associated
            %   input has been set high since the last reset. This is a 16-bit counter,
            %   meaning it can store values up to 65535 (ie. 1111 1111 1111 1111).

            if nargin ~= 2
                error('vellboard:ImproperArguments',['Calling syntax: obj.readCounter(counter)' char(10) ...
                    'Where counter = counter to be read (1 <= counter <= 2)'])
            end
            
            validateattributes(counter,{'numeric'},{'scalar','integer','>=',1,'<=',2});
            
            if obj.testmode
                result = 0;
            else
                result = calllib('K8055D','ReadCounter',counter);
            end
        end
        
        %% Reads the value of both pulse counters
        function result = readCounterAll(obj)
            % result = ExperimentBoard.readCounterAll()
            %   Reads the current value for both counters in one function call.
            %   Returns a 1x2 vector, with each entry of the vector corresponding to
            %   a counter. For example, result(1) is the current value of the counter
            %   associated with digital input 1.
            
            
            
            if obj.testmode
                result = [0 0];
            else
                data1 = calllib('K8055D','ReadCounter',1);
                data2 = calllib('K8055D','ReadCounter',2);
                result = [data1 data2];
            end
        end
        
        %% Resets pulse counter #"counter"
        function resetCounter(obj,counter)
            % ExperimentBoard.resetCounter(counter)
            %   Resets the counter for the digital input defined by counter (only
            %   digital inputs 1 and 2 have counter functionality) to 0.
            if nargin ~= 2
                error('vellboard:ImproperArguments',['Calling syntax: obj.resetCounter(counter)' char(10) ...
                    'Where counter = counter to be reset (1 <= counter <= 2)'])
            end
            
            validateattributes(counter,{'numeric'},{'scalar','integer','>=',1,'<=',2});
            
            if ~obj.testmode
                calllib('K8055D','ResetCounter',counter);
            end
        end    
        
        %% Sets the debounce time for counter #"counter" to "debouncetime"
        function setCounterDebounceTime(obj,counter,debouncetime)
            % ExperimentBoard.setCounterDebounceTime(counter,debouncetime)
            %   Sets the debounce time for the counter associated with the digital
            %   input defined by counter (only inputs 1 and 2 have counter
            %   functionality) to the value set by debouncetime. debouncetime is
            %   measured in milliseconds and can be any integer between 0 and 5000. The
            %   counter debounce time represents the time the input must be high for
            %   the counter to increase. For example, if the debounce time is set to
            %   5ms, only pulses that are at least 5ms long will increment the timer.

            if nargin ~= 3
                error('vellboard:ImproperArguments',['Calling syntax: obj.setCounterDebounceTime(counter,debouncetime)' char(10) ...
                    'Where counter = counter to be set (1 <= counter <= 2)' char(10) ...
                    'and debouncetime = debounce time to be set in ms (0 <= debouncetime <= 5000)'])
            end
            
            validateattributes(counter,{'numeric'},{'scalar','integer','>=',1,'<=',2});
            validateattributes(debouncetime,{'numeric'},{'scalar','integer','>=',0,'<=',5000});
            
            if ~obj.testmode
                calllib('K8055D','SetCounterDebounceTime',counter,debouncetime);
            end
        end
        
        %% Returns the DLL version as a string in X.X.X.X format
        function result = version(obj)            
            % ExperimentBoard.version()
            %   Returns the version of the K8055 SDK's DLL library as a string in
            %   X.X.X.X format. Note that the Support Package was written using version
            %   4.0.0.0 of this DLL; any other versions may cause compatibility errors.

            version = cast(calllib('K8055D','Version'),'int32');
            
            version = typecast(version,'int8');
            result = [num2str(version(4)) '.' ...
                num2str(version(3)) '.' ...
                num2str(version(2)) '.' ...
                num2str(version(1))];
        end
        
        %% custom display function
        function display(obj)
            fprintf('\nvellboard.ExperimentBoard object\n');
            fprintf('   <a href="matlab:help vellboard.ExperimentBoard">>Class help</a>\n');
            fprintf('   <a href="matlab:vellboard.ExperimentBoard.getMethods()">>Methods</a>\n');
            fprintf('\n')
        end
    end
    
    %% static methods
    methods(Static)
        %% nicely formatted methods list with help links
        function getMethods()
            % ExperimentBoard.getMethods()
            %   Prints a nicely formatted list of ExperimentBoard's methods with links
            %   to their relevant help dialogs.
            fprintf('\nMethods for vellboard.ExperimentBoard:\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.ExperimentBoard">ExperimentBoard()</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.delete">delete()</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.getActiveDevices">getActiveDevices()</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.setCurrentDevice">setCurrentDevice(boardaddress)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.readAnalog">readAnalog(channel)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.readAnalogAll">readAnalogAll()</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.writeAnalog">writeAnalog(channel,data)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.writeAnalogAll">writeAnalogAll(datavec)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.readDigital">readDigital(channel)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.readDigitalAll">readDigitalAll()</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.writeDigital">writeDigital(channel,data)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.writeDigitalAll">writeDigitalAll(datavec)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.readCounter">readCounter(counter)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.readCounterAll">readCounterAll()</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.resetCounter">resetCounter(counter)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.setCounterDebounceTime">setCounterDebounceTime(counter,debouncetime)</a>\n');
            fprintf('    <a href="matlab:help vellboard.ExperimentBoard.version">version()</a>\n');
            fprintf('\n');
        end
    end
    
end

Contact us