Skip to content
Snippets Groups Projects
Commit 5109a72e authored by Tim Stadtmann's avatar Tim Stadtmann
Browse files

Extend and improve error-handling in BrickIO-layer

I also added a function that returns an ID to be used as an
error identifier and adapted the previously implemented
error handling to it.
parent 8555db2a
No related branches found
No related tags found
No related merge requests found
function id = ID()
% Generates a string that serves as an ID for a calling function
toolbox = 'RWTHMindstormsEV3';
% Get stack trace
stackTrace = dbstack();
% Element on top of stack is this function (ID()), second element is caller
callerList = strsplit(stackTrace(2).name, '.');
% The anticipated format of the caller is classname.functionname
functionName = callerList{length(callerList)};
% Create id
if length(callerList) > 1
className = callerList{length(callerList)-1};
id = [toolbox, ':', className, ':', functionName];
else
id = [toolbox, ':', functionName];
end
end
......@@ -53,9 +53,27 @@ classdef btBrickIO < BrickIO
if brickIO.debug > 0
fprintf('btBrickIO init\n');
end
% set the connection handle
% Set the connection handle
try
brickIO.handle = serial(brickIO.serialPort);
% open the connection handle
catch ME
if ~isempty(strfind(ME.identifier, 'invalidPORT'))
% Throw a clean InvalidSerialPort to avoid confusion in upper layers
msg = 'Couldn''t connect to BT-device because given serial port is invalid.';
id = [ID(), ':', 'InvalidSerialPort'];
throw(MException(id, msg));
else
% Throw combined error because error did not happen due to known reasons...
msg = 'Unknown error occurred while creating serial-port-object for BT connection.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);
end
end
% Open the connection handle
brickIO.open;
end
......@@ -79,23 +97,24 @@ classdef btBrickIO < BrickIO
if brickIO.debug > 0
fprintf('btBrickIO open\n');
end
% open the bt handle (MMI: and handle possible errors)
% Open the bt handle
try
fopen(brickIO.handle);
catch ME
if strcmp(ME.identifier, 'MATLAB:serial:fopen:opfailed')
% Throw only clean commError to avoid confusion in upper layers
msg = ['Failed to connect to Brick via Bluetooth.'] ;
id = 'MATLAB:RWTHMindstormsEV3:btBrickIO:open:commError';
msg = 'Failed to connect to Brick via Bluetooth.';
id = [ID(), ':', 'commError'];
throw(MException(id, msg));
else
% Throw combined error because error did not happen due to communication
% failure
msg = ['Unknown error occurred while connecting to the Brick via Bluetooth.'];
id = 'MATLAB:RWTHMindstormsEV3:btBrickIO:open:unknownError';
causeException = MException(id, msg);
ME = addCause(ME, causeException);
rethrow(ME);
msg = 'Unknown error occurred while connecting to the Brick via Bluetooth.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);
end
end
end
......@@ -109,8 +128,19 @@ classdef btBrickIO < BrickIO
if brickIO.debug > 0
fprintf('btBrickIO close\n');
end
% close the close handle
try
% Close the close handle
fclose(brickIO.handle);
catch ME
% Throw combined error because error did not happen due to communication
% failure
msg = 'Unknown error occurred while disconnecting from the Brick via Bluetooth.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);
end
end
function rmsg = read(brickIO)
......@@ -122,11 +152,23 @@ classdef btBrickIO < BrickIO
if brickIO.debug > 0
fprintf('btBrickIO read\n');
end
% get the number of bytes to be read from the bt handle
try
% Get the number of bytes to be read from the bt handle
nLength = fread(brickIO.handle,2);
% read the remaining bytes
% Read the remaining bytes
rmsg = fread(brickIO.handle,double(typecast(uint8(nLength),'uint16')));
% append the reply size to the return message
catch ME
% Throw combined error because error did not happen due to known reasons...
msg = 'Unknown error occurred while reading data from the Brick via BT.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);
end
% Append the reply size to the return message
rmsg = uint8([nLength' rmsg']);
end
......@@ -143,7 +185,18 @@ classdef btBrickIO < BrickIO
if brickIO.debug > 0
fprintf('btBrickIO write\n');
end
try
% Write to the bluetooth handle
fwrite(brickIO.handle,wmsg);
catch ME
% Throw combined error because error did not happen due to known reasons...
msg = 'Unknown error occurred while sending data to the Brick via BT.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);
end
end
end
end
\ No newline at end of file
......@@ -19,6 +19,7 @@
% error Return the error string
% enumerate Enumerate the connected hid devices
%
%
% Example::
% hid = hidapi(1,1684,0005,1024,1025)
%
......@@ -61,6 +62,11 @@ classdef hidapi < handle
% checking is required in this function to load the correct
% library.
%
% Throws::
% LoadingLibraryError Could not load .dll/.dylib/.so-file of hidapi
% InvalidParameterOrFileMissing Either file names given were wrong or the files are missing
% (e.g. thunk files, proto files, ...)
%
% Notes::
% - debug is a flag specifying output printing (0 or 1).
% - vendorID is the vendor ID of the hid device (decimal not hex).
......@@ -68,6 +74,7 @@ classdef hidapi < handle
% - nReadBuffer is the length of the read buffer.
% - nWriteBuffer is the length of the write buffer.
hid.debug = debug;
if hid.debug > 0
......@@ -81,14 +88,9 @@ classdef hidapi < handle
hid.nWriteBuffer = nWriteBuffer;
end
% Disable the type not found for structure warning
% Disable warnings
warning('off','MATLAB:loadlibrary:TypeNotFoundForStructure');
if libisloaded('hidapiusb')
%warning('RWTHMindstormsEV3:hidapi:hidapi:LibraryAlreadyLoaded', ...
%'Library for USB-connection has already been loaded. Unloading...');
unloadlibrary('hidapiusb');
end
warning('off', 'MATLAB:loadlibrary:ClassIsLoaded');
try
% Check the operating system type and load slib
......@@ -116,7 +118,7 @@ classdef hidapi < handle
end
catch ME
% Create own exception for clarification
id = 'RWTHMindstormsEV3:hidapi:hidapi:LoadingLibraryError';
id = [ID(), ':', 'LoadingLibraryError'];
msg = strcat({'Could not load library '}, {hid.slib}, {'.'});
exception = MException(id, msg);
......@@ -124,7 +126,7 @@ classdef hidapi < handle
if isempty(findstr(ME.identifier, 'LoadFailed')) ...
&& isempty(findstr(ME.identifier, 'ErrorLoadingLibrary')) ...
&& isempty(findstr(ME.identifier, 'ErrorInHeader'))
id = 'RWTHMindstormsEV3:hidapi:hidapi:InvalidParameterOrFileMissing';
id = [ID(), ':', 'InvalidParameterOrFileMissing'];
msg = 'Invalid parameters were given or files are not available.';
cause = MException(id, msg);
exception = addCause(exception, cause);
......@@ -132,7 +134,6 @@ classdef hidapi < handle
throw(exception);
end
% Remove the library extension
hid.slib = 'hidapiusb';
......@@ -141,8 +142,6 @@ classdef hidapi < handle
end
end
%% Wrapper
function delete(hid)
%hidapi.delete Delete hid object
%
......@@ -156,10 +155,10 @@ classdef hidapi < handle
if hid.debug > 0
fprintf('hidapi delete\n');
end
hid.close();
end
%% Wrapper
function str = getManufacturersString(hid)
%hidapi.getManufacturersString get manufacturers string from hid object
%
......@@ -196,6 +195,9 @@ classdef hidapi < handle
% initialised values of vendorID and productID from the hidapi
% constructor.
%
% Throws::
% CommError Error during communication with device
%
% Notes::
% - The pointer return value from this library call is always
% null so it is not possible to know if the open was
......@@ -221,7 +223,7 @@ classdef hidapi < handle
% (MMI) Assert error case (hid_open returns null-pointer in error case)
assert(isLibPointerValid(newHandle)==1, ...
'RWTHMindstormsEV3:hidapi:open:CommError', ...
[ID(), ':', 'CommError'], ...
'Failed to connect to USB device.');
hid.handle = newHandle;
......@@ -232,6 +234,10 @@ classdef hidapi < handle
%
% hid.close() closes the connection to a hid device. Gets called automatically
% when deleting the hid instance.
%
% Throws::
% InvalidHandle Handle to USB-device not valid
%
if hid.debug > 0
fprintf('hidapi close\n');
......@@ -239,7 +245,7 @@ classdef hidapi < handle
% (MMI) Check if pointer is (unexpectedly) already invalidated
assert(isLibPointerValid(hid.handle)==1, ...
'RWTHMindstormsEV3:hidapi:close:InvalidHandle', ...
[ID(), ':', 'InvalidHandle'], ...
'Failed to close USB-connection because pointer to USB-device is already invalidated.');
% Close the connection
......@@ -254,6 +260,11 @@ classdef hidapi < handle
%
% rmsg = hid.read() reads from a hid device and returns the
% read bytes. Will print an error if no data was read.
%
% Throws::
% CommError Error during communication with device
% InvalidHandle Handle to USB-device not valid
%
if hid.debug > 0
fprintf('hidapi read\n');
......@@ -266,7 +277,7 @@ classdef hidapi < handle
% (MMI) Check if pointer is (unexpectedly) already invalidated
assert(isLibPointerValid(hid.handle)==1, ...
'RWTHMindstormsEV3:hidapi:read:InvalidHandle', ...
[ID(), ':', 'InvalidHandle'], ...
'Failed to read USB-data because pointer to USB-device is invalidated.');
% Read data from HID device
......@@ -274,7 +285,7 @@ classdef hidapi < handle
% (MMI) Check the response
assert(res>=1, ...
'RWTHMindstormsEV3:hidapi:read:CommError', ...
[ID(), ':', 'CommError'], ...
'Failed to read data via USB.');
% Return the string value
......@@ -287,6 +298,11 @@ classdef hidapi < handle
% hid.write() writes to a hid device. Will print an error if
% there is a mismatch between the buffer size and the reported
% number of bytes written.
%
% Throws::
% CommError Error during communication with device
% InvalidHandle Handle to USB-device not valid
%
if hid.debug > 0
fprintf('hidapi write\n');
......@@ -307,7 +323,7 @@ classdef hidapi < handle
% (MMI) Check if pointer is (unexpectedly) already invalidated
assert(isLibPointerValid(hid.handle)==1, ...
'RWTHMindstormsEV3:hidapi:read:InvalidHandle', ...
[ID(), ':', 'InvalidHandle'], ...
'Failed to write to USB because pointer to USB-device is invalidated.');
% Write the message
......@@ -315,7 +331,7 @@ classdef hidapi < handle
% (MMI) Check the response
assert(res == length(wmsg), ...
'RWTHMindstormsEV3:hidapi:write:CommError', ...
[ID(), ':', 'CommError'], ...
'Failed to write data via USB.');
end
......@@ -325,6 +341,10 @@ classdef hidapi < handle
% hid.getHIDInfoString(info) gets the corresponding hid info
% from the hid device
%
% Throws::
% CommError Error during communication with device
% InvalidHandle Handle to USB-device not valid
%
% Notes::
% - info is the hid information string.
......@@ -342,7 +362,7 @@ classdef hidapi < handle
% (MMI) Check if pointer is (unexpectedly) already invalidated
assert(isLibPointerValid(hid.handle)==1, ...
'RWTHMindstormsEV3:hidapi:getHIDInfoString:InvalidHandle', ...
[ID(), ':', 'InvalidHandle'], ...
'Failed to read USB-data because pointer to USB-device is invalidated.');
% Get the HID info string
......@@ -350,7 +370,7 @@ classdef hidapi < handle
% (MMI) Check the response
assert(res~=-1, ...
'RWTHMindstormsEV3:hidapi:getHIDInfoString:CommError', ...
[ID(), ':', 'CommError'], ...
'Failed to read HID info string.');
% Return the string value
......@@ -363,6 +383,10 @@ classdef hidapi < handle
% hid.setNonBlocking(nonblock) sets the non blocking flag on
% the hid device connection.
%
% Throws::
% CommError Error during communication with device
% InvalidHandle Handle to USB-device not valid
%
% Notes::
% nonblock - 0 disables nonblocking, 1 enables nonblocking
......@@ -372,7 +396,7 @@ classdef hidapi < handle
% (MMI) Check if pointer is (unexpectedly) already invalidated
assert(isLibPointerValid(hid.handle)==1, ...
'RWTHMindstormsEV3:hidapi:setNonBlocking:InvalidHandle', ...
[ID(), ':', 'InvalidHandle'], ...
'Failed to set USB-read-mode to non-blocking because pointer to USB-device is invalidated.');
% Set non blocking
......@@ -380,7 +404,7 @@ classdef hidapi < handle
% (MMI) Check the response
assert(res~=-1, ...
'RWTHMindstormsEV3:hidapi:setNonBlocking:CommError', ...
[ID(), ':', 'CommError'], ...
'Failed to set USB-read-mode to non-blocking.');
end
......@@ -390,6 +414,9 @@ classdef hidapi < handle
% hid.init() inits the hidapi library. This is called
% automatically in the library itself with the open function.
%
% Throws::
% CommError Error during communication with device
%
% Notes::
% - You should not have to call this function directly.
......@@ -397,7 +424,7 @@ classdef hidapi < handle
fprintf('hidapi init\n');
end
warning('RWTHMindstormsEV3:hidapi:init:RedundantCall', ...
warning([ID(), ':', 'RedundantCall'], ...
'The init-function gets called automatically when connecting!');
% Init device
......@@ -405,7 +432,7 @@ classdef hidapi < handle
% (MMI) Check the response
assert(res~=-1, ...
'RWTHMindstormsEV3:hidapi:init:CommError', ...
[ID(), ':', 'CommError'], ...
'Failed to init USB-device.');
end
......@@ -414,6 +441,9 @@ classdef hidapi < handle
%
% hid.exit() exits the hidapi library.
%
% Throws::
% CommError Error during communication with device
%
% Notes::
% - You should not have to call this function directly.
......@@ -421,7 +451,7 @@ classdef hidapi < handle
fprintf('hidapi exit\n');
end
warning('RWTHMindstormsEV3:hidapi:exit:RedundantCall', ...
warning([ID(), ':', 'RedundantCall'], ...
'The exit-function gets called automatically when disconnecting!');
% Exit device
......@@ -429,7 +459,7 @@ classdef hidapi < handle
% (MMI) Check the response
assert(res~=-1, ...
'RWTHMindstormsEV3:hidapi:exit:CommError', ...
[ID(), ':', 'CommError'], ...
'Failed to exit USB-device.');
end
......@@ -439,6 +469,9 @@ classdef hidapi < handle
% hid.error() returns the hid device error string if a function
% produced an error.
%
% Throws::
% InvalidHandle Handle to USB-device not valid
%
% Notes::
% - This function must be called explicitly if you think an
% error was generated from the hid device.
......@@ -449,7 +482,7 @@ classdef hidapi < handle
% (MMI) Check if pointer is (unexpectedly) already invalidated
assert(isLibPointerValid(hid.handle)==1, ...
'RWTHMindstormsEV3:hidapi:error:InvalidHandle', ...
[ID(), ':', 'InvalidHandle'], ...
'Failed to read USB-error-data because pointer to USB-device is invalidated.');
[~,str] = calllib(hid.slib,'hid_error',hid.handle);
......
......@@ -57,8 +57,31 @@ classdef usbBrickIO < BrickIO
end
% Create the usb handle
try
brickIO.handle = hidapi(0,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 brick IO connection
brickIO.open;
......@@ -85,22 +108,23 @@ classdef usbBrickIO < BrickIO
if brickIO.debug > 0
fprintf('usbBrickIO open\n');
end
% open the usb handle (MMI: and handle possible errors)
% Open the usb handle (MMI: and handle possible errors)
try
brickIO.handle.open;
catch ME
if ~isempty(findstr(ME.identifier, 'CommError'))
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 = 'MATLAB:RWTHMindstormsEV3:usbBrickIO:write:CommError';
throw(MException(msg, id));
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 = 'MATLAB:RWTHMindstormsEV3:btBrickIO:open:UnknownError';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(ME);
throw(newException);
end
end
end
......@@ -113,8 +137,18 @@ classdef usbBrickIO < BrickIO
if brickIO.debug > 0
fprintf('usbBrickIO close\n');
end
% close the usb handle
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 reading data from the Brick via BT.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);
end
end
function rmsg = read(brickIO)
......@@ -130,27 +164,28 @@ classdef usbBrickIO < BrickIO
if brickIO.debug > 0
fprintf('usbBrickIO read\n');
end
% read from the usb handle
% Read from the usb handle
try
rmsg = brickIO.handle.read;
catch ME
if ~isempty(findstr(ME.identifier, 'CommError'))
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 = 'MATLAB:RWTHMindstormsEV3:usbBrickIO:read:CommError';
throw(MException(msg, id));
elseif ~isempty(findstr(ME.identifier, 'InvalidHandle'))
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 = 'MATLAB:RWTHMindstormsEV3:usbBrickIO:read:InvalidHandle';
throw(MException(msg, id));
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 = 'MATLAB:RWTHMindstormsEV3:usbBrickIO:read:UnknownError';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(ME);
throw(newException);
end
end
......@@ -173,7 +208,7 @@ classdef usbBrickIO < BrickIO
if nLength+2 < length(rmsg)
rmsg = rmsg(1:nLength+2);
else
warning('MATLAB:RWTHMindstormsEV3:usbBrickIO:read:CorruptPacket', ...
warning([ID(), ':', 'CorruptPacket'], ...
'Returned packet''s length doesn''t equal its length indicator (bytes 1 & 2).');
end
......@@ -196,23 +231,23 @@ classdef usbBrickIO < BrickIO
try
brickIO.handle.write(wmsg,0);
catch ME
if ~isempty(findstr(ME.identifier, 'CommError'))
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 = 'MATLAB:RWTHMindstormsEV3:usbBrickIO:write:CommError';
throw(MException(msg, id));
elseif ~isempty(findstr(ME.identifier, 'InvalidHandle'))
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 = 'MATLAB:RWTHMindstormsEV3:usbBrickIO:write:InvalidHandle';
throw(MException(msg, id));
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 = 'MATLAB:RWTHMindstormsEV3:btBrickIO:open:UnknownError';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(ME);
throw(newException);
end
end
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment