Skip to content
Snippets Groups Projects
Select Git revision
  • c8151c5e9cb14037cd78f43aa857a9c0dd5c9de5
  • master default protected
  • dev_2022
  • patch-1
  • develop
  • 50-use-ubuntus-libhidapi
  • issue-highLevelDispatch
  • issue-highLevelDesign
  • issue-motorStartBug
  • issue-commandLayerDesign
  • v1.0
  • v0.4-rc.13
  • v0.4-rc.12
  • v0.4-rc.11
  • v0.4-rc.10
  • v0.4-rc.9
  • v0.3-rc.8
  • v0.3-rc.7
  • v0.3-rc.6
  • v0.3-rc.5
  • v0.3-rc.4
  • v0.3-rc.3
  • v0.3-rc.2
  • v0.3-rc.1
  • v0.3-rc
  • v0.2
  • v0.1.1
  • v0.1
28 results

usbBrickIO.m

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    usbBrickIO.m 12.33 KiB
    classdef usbBrickIO < BrickIO      
        % USB interface between MATLAB and the brick
        %
        % Notes:
        %     * Uses the hid library implementation in hidapi.m
        %     * The default parameters should always work when you try to connect to an EV3 brick,
        %       so in nearly all use-cases, the constructor does not need any parameters (besides
        %       'debug' eventually).
        %
        % Attributes:
        %     debug (bool): If true, each open/close/read/write-call will be noted in the console.
        %        Defaults to false.
        %     vendorID (numeric): Vendor-ID of the USB device. Defaults to 0x694 (EV3 vendor ID).
        %     productID (numeric): Product-ID of the USB device. Defaults to 0x0005 (EV3 product ID).
        %     nReadBuffer (numeric): Read-buffer size in bytes. Defaults to 1024.
        %     nWriteBuffer (numeric): Write-buffer size in bytes. Needs to be 1 Byte bigger than
        %        actual packet. Defaults to 1025 (EV3 USB maximum packet size = 1024).
        %     timeOut (numeric >= 0): Milliseconds after which a timeout-error occurs if no packet could be
        %        read. Defaults to 10000.
        %
        % ::
        %
        %     Examples:
        %         % Connecting via USB 
        %         commHandle = usbBrickIO();
        %         % Connecting via USB with enabled debug output
        %         commHandle = usbBrickIO('debug', true);
        %
        
        properties
            % debug (bool): If true, each open/close/read/write-call will be noted in the console.
            %    Defaults to false.
            debug;
            % vendorID (numeric): Vendor-ID of the USB device. Defaults to 0x694 (EV3 vendor ID).
            vendorID;
            % productID (numeric): Product-ID of the USB device. Defaults to 0x0005 (EV3 product ID).
            productID;
            % nReadBuffer (numeric): Read-buffer size in bytes. Defaults to 1024.
            nReadBuffer;
            % nWriteBuffer (numeric): Write-buffer size in bytes. Defaults to 1025 (EV3 USB maximum packet size = 1024).
            %    Needs to be 1 Byte bigger than actual packet. 
            nWriteBuffer;
            % timeOut (numeric >= 0): Milliseconds after which a timeout-error occurs if no packet could be read. Defaults to 10000.
            timeOut;
        end
        
        properties (Access = protected)
            % handle: Connection handle to the device
            handle
        end 
        
        methods
            function brickIO = usbBrickIO(varargin)
                % Create an usbBrickIO object 
                %
                % Arguments:
                %     varargin: Any number of property names as strings, each followed by the
                %         desired value. 
                %
                % ::
                %
                %     Examples: 
                %         % Connecting via USB 
                %         commHandle = usbBrickIO();
                %         % Connecting via USB with enabled debug output
                %         commHandle = usbBrickIO('debug', true);
                %
                % See also USBBRICKIO.SETPROPERTIES
                
                brickIO.setProperties(varargin{:});
                
                if brickIO.debug > 0
                    fprintf('\t(DEBUG) (USB init)\n');
                end
                
                % Set the connection handle
                try
                    brickIO.handle = hidapi(brickIO.vendorID,brickIO.productID, ...
                                            brickIO.nReadBuffer,brickIO.nWriteBuffer);
                catch ME
                    if ~isempty(strfind(ME.identifier, 'InvalidParameterOrFileMissing'))
                        % Throw a clean InvalidParameterOrFileMissing to avoid confusion in upper layers
                        msg = ['Couldn''t load hidapi-library for USB connection due to a ' ...
                               'missing file. Make sure the correct hidapi-library and its ' ...
                               'corresponding thunk- and proto-files are available.'];
                        id = [ID(), ':', 'InvalidParameterOrFileMissing'];
                        throw(MException(id, msg));
                    elseif ~isempty(strfind(ME.identifier, 'LoadingLibraryError'))
                        % Throw a clean LoadingLibraryError to avoid confusion in upper layers
                        msg = 'Failed to load hidapi-library for USB connection.';
                        id = [ID(), ':', 'LoadingLibraryError'];
                        throw(MException(id, msg));
                    else
                        % Throw combined error because error did not happen due to known reasons...
                        msg = 'Unknown error occurred while trying to load the HIDAPI-lib for USB.';
                        id = [ID(), ':', 'UnknownError'];
                        newException = MException(id, msg);
                        newException = addCause(newException, ME);
                        throw(newException);
                    end
                end
                                    
                % Open the connection
                brickIO.open;
            end
            
            function delete(brickIO)
                % Delete the usbBrickIO object and closes the connection
                
                if brickIO.debug > 0
                    fprintf('\t(DEBUG) (USB delete)\n');
                end
                
                % Disconnect
                try
                    brickIO.close;
                catch
                    % Connection already closed (probably due to an error) - do nothing
                end
            end
            
            function open(brickIO)
                % Opens the usb connection to the brick through the hidapi interface.
                
                if brickIO.debug > 0
                    fprintf('\t(DEBUG) (USB open)\n');
                end
                
                % Open the usb handle 
                try
                    brickIO.handle.open;
                catch ME
                    if ~isempty(strfind(ME.identifier, 'CommError'))
                        % Throw a clean CommError to avoid confusion in upper layers
                        msg = 'Failed to open connection to Brick via USB.';
                        id = [ID(), ':', 'CommError'];
                        throw(MException(id, msg));
                    else
                        % Throw combined error because error did not happen due to known reasons...
                        msg = 'Unknown error occurred while trying to connect to the Brick via USB.';
                        id = [ID(), ':', 'UnknownError'];
                        newException = MException(id, msg);
                        newException = addCause(newException, ME);
                        throw(newException);
                    end
                end
            end
            
            function close(brickIO)
                % Closes the usb connection the brick through the hidapi interface.
                
                if brickIO.debug > 0
                    fprintf('\t(DEBUG) (USB close) \n');
                end 
                
                try
                    % Close the usb handle
                    brickIO.handle.close;
                catch ME
                    % Throw combined error because error did not happen due to known reasons...
                    msg = 'Unknown error occurred while closing the USB connection.';
                    id = [ID(), ':', 'UnknownError'];
                    newException = MException(id, msg);
                    newException = addCause(newException, ME);
                    throw(newException);
                end
            end
            
            function rmsg = read(brickIO)
                % Reads data from the brick through usb using the hidapi interface and returns the data in uint8 format.
                
                if brickIO.debug > 0
                    fprintf('\t(DEBUG) (USB read)   ');
                end 
                
                % Read from the usb handle
                try
                    if brickIO.timeOut ~= 0
                        rmsg = brickIO.handle.read_timeout(brickIO.timeOut);
                    else
                        rmsg = brickIO.handle.read();
                    end
                catch ME
                    if ~isempty(strfind(ME.identifier, 'CommError'))
                        % Throw a clean CommError to avoid confusion in upper layers
                        msg = 'Failed to read data from the Brick via USB due to connection-error.';
                        id = [ID(), ':', 'CommError'];
                        throw(MException(id, msg));
                    elseif ~isempty(strfind(ME.identifier, 'InvalidHandle'))
                        % Throw a clean InvalidHandle to avoid confusion in upper layers
                        msg = 'Failed to read data from the Brick via USB due to invalid handle to USB-device.';
                        id = [ID(), ':', 'InvalidHandle'];
                        throw(MException(id, msg));
                    else
                        % Throw combined error because error did not happen due to known reasons...
                        msg = 'Unknown error occurred while reading data from the Brick via USB.';
                        id = [ID(), ':', 'UnknownError'];
                        newException = MException(id, msg);
                        newException = addCause(newException, ME);
                        throw(newException);
                    end
                end
                
                % Get the number of read bytes
                pLength = double(typecast(uint8(rmsg(1:2)),'uint16')) + 2;
                
                % Format the read message (2 byte length plus message)
                if pLength < length(rmsg)
                    rmsg = rmsg(1:pLength);
                end
            end
            
            function write(brickIO,wmsg)
                % Writes data to the brick through usb using the hidapi interface.
                %
                % Arguments:
                %     wmsg (uint8 array): Data to be written to the brick via usb
                
                if brickIO.debug > 0
                    fprintf('\t(DEBUG) (USB write)  ');
                end 
                
                % Write to the usb handle using report ID 0
                try
                    brickIO.handle.write(wmsg,0);
                catch ME
                    if ~isempty(strfind(ME.identifier, 'CommError'))
                        % Throw a clean CommError to avoid confusion in upper layers
                        msg = 'Failed to send data to Brick via USB due to connection-error.';
                        id = 'RWTHMindstormsEV3:usbBrickIO:write:CommError';
                        throw(MException(id, msg));
                    elseif ~isempty(strfind(ME.identifier, 'InvalidHandle'))
                        % Throw a clean InvalidHandle to avoid confusion in upper layers
                        msg = 'Failed to send data to Brick via USB due to invalid handle to USB-device.';
                        id = [ID(), ':', 'InvalidHandle'];
                        throw(MException(id, msg));
                    else
                        % Throw combined error because error did not happen due to known reasons...
                        msg = 'Unknown error occurred while sending data to the Brick via USB.';
                        id = [ID(), ':', 'UnknownError'];
                        newException = MException(id, msg);
                        newException = addCause(newException, ME);
                        throw(newException);
                    end
                end
            end
            
            function set.timeOut(brickIO, timeOut)
                if ~isnumeric(timeOut) || timeOut < 0
                    error(ID(), 'timeOut-period of USB-handle can only be set to positive numerical values.'); 
                end
                
                brickIO.timeOut = timeOut*1000;
            end 
            function setProperties(brickIO, varargin)
                % Sets multiple usbBrickIO properties at once using MATLAB's inputParser.
                %
                % The syntax is as follows: commHandle.setProperties('propertyName1',
                % propertyValue1, 'propertyName2', propertyValue2, ...). Valid, optional properties
                % are: debug, vendorID, productID, nReadBuffer, nWriteBuffer, timeOut.
                %
                % See also USBBRICKIO.DEBUG, USBBRICKIO.VENDORID, USBBRICKIO.PRODUCTID,
                % USBBRICKIO.NREADBUFFER, USBBRICKIO.NWRITEBUFFER, USBBRICKIO.TIMEOUT
                
                p = inputParser();
                
                p.addOptional('debug', false);
                p.addOptional('vendorID', 1684);
                p.addOptional('productID', 5);
                p.addOptional('nReadBuffer', 1024);
                p.addOptional('nWriteBuffer', 1025);
                p.addOptional('timeOut', 10000);
                
                p.parse(varargin{:});
                
                brickIO.debug = p.Results.debug;
                brickIO.vendorID = p.Results.vendorID;
                brickIO.productID = p.Results.productID;
                brickIO.nReadBuffer = p.Results.nReadBuffer;
                brickIO.nWriteBuffer = p.Results.nWriteBuffer;
                brickIO.timeOut = p.Results.timeOut;
            end
        end 
    end