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

Update error-handling

Enhances previous error-handling commits: new errors will be
recognized, more detailed error messages, implementation in more
functions, ..
parent 1762012b
No related branches found
No related tags found
No related merge requests found
......@@ -162,66 +162,52 @@ classdef Brick < handle
opt.wfSN = '0016533dbaf5';
opt.ioType = 'usb';
opt.serPort = '/dev/rfcomm0';
% read in the options
% Read in the options
opt = tb_optparse(opt, varargin);
% select the connection interface
connect = 0;
% usb
if(strcmp(opt.ioType,'usb'))
brick.debug = opt.debug;
brick.ioType = opt.ioType;
brick.conn = usbBrickIO(brick.debug);
connect = 1;
end
% wifi
if(strcmp(opt.ioType,'wifi'))
brick.debug = opt.debug;
brick.ioType = opt.ioType;
brick.wfAddr = opt.wfAddr;
brick.wfPort = opt.wfPort;
brick.wfSN = opt.wfSN;
brick.conn = wfBrickIO(brick.debug,brick.wfAddr,brick.wfPort,brick.wfSN);
connect = 1;
end
% bluetooth
if(strcmp(opt.ioType,'bt'))
brick.debug = opt.debug;
brick.ioType = opt.ioType;
brick.serPort = opt.serPort;
brick.conn = btBrickIO(brick.debug,brick.serPort);
connect = 1;
end
% instrumentation and control wifi
if(strcmp(opt.ioType,'instrwifi'))
brick.debug = opt.debug;
brick.ioType = opt.ioType;
brick.wfAddr = opt.wfAddr;
brick.wfPort = opt.wfPort;
brick.wfSN = opt.wfSN;
brick.conn = instrBrickIO(brick.debug,'wf',brick.wfAddr,brick.wfPort,brick.wfSN);
connect = 1;
end
% instrumentation and control bluetooth
if(strcmp(opt.ioType,'instrbt'))
brick.debug = opt.debug;
brick.ioType = opt.ioType;
brick.btDevice = opt.btDevice;
brick.btChannel = opt.btChannel;
brick.conn = instrBrickIO(brick.debug,'bt',brick.btDevice,brick.btChannel);
connect = 1;
end
% error
if(~connect)
fprintf('Please specify a serConn option: ''usb'',''wifi'',''bt'',''instrwifi'' or ''instrbt''.\n');
brick.debug = opt.debug;
brick.ioType = opt.ioType;
try
if(strcmp(opt.ioType,'usb')) % USB
brick.conn = usbBrickIO(brick.debug);
elseif(strcmp(opt.ioType,'wifi')) % WiFi
brick.wfAddr = opt.wfAddr;
brick.wfPort = opt.wfPort;
brick.wfSN = opt.wfSN;
brick.conn = wfBrickIO(brick.debug,brick.wfAddr,brick.wfPort,brick.wfSN);
elseif(strcmp(opt.ioType,'bt')) % Bluetooth
brick.serPort = opt.serPort;
brick.conn = btBrickIO(brick.debug,brick.serPort);
elseif(strcmp(opt.ioType,'instrwifi')) % Instrumentation and Control: WiFi
brick.wfAddr = opt.wfAddr;
brick.wfPort = opt.wfPort;
brick.wfSN = opt.wfSN;
brick.conn = instrBrickIO(brick.debug,'wf',brick.wfAddr,brick.wfPort,brick.wfSN);
elseif(strcmp(opt.ioType,'instrbt')) % Instrumentation and Control: Bluetooth
brick.btDevice = opt.btDevice;
brick.btChannel = opt.btChannel;
brick.conn = instrBrickIO(brick.debug,'bt',brick.btDevice,brick.btChannel);
end
catch ME
brick.conn = [];
rethrow(ME);
end
end
function set.debug(brick, debug)
% If debug is set in this layer, also set BrickIO.debug in lower layer
brick.debug = debug;
brick.conn.debug = debug;
end
function delete(brick)
% Brick.delete Delete the Brick object
%
% delete(b) closes the connection to the brick
delete(brick.conn);
if isa(brick.conn, 'handle') && isvalid(brick.conn)
brick.conn.delete();
end
end
function send(brick, cmd)
......@@ -267,13 +253,63 @@ classdef Brick < handle
% rmsg = Brick.receive() receives data from the brick through
% the connection handle.
%
% Notes:
% - If received packet is corrupt, up to five new packets are read (if all are
% corrupt, an error is thrown)
%
% Example::
% rmsg = b.receive()
% read the message through the brickIO read function
%
% Read the message through the brickIO read function
rmsg = brick.conn.read();
% Check if reply is corrupt or error byte is set
try
reply = Command(rmsg);
catch ME
corrupt = 1;
if ~isempty(strfind(ME.identifier, 'CorruptPacket'))
% Read packet was corrupt - retry
id = [ID(), ':', 'CorruptPacket'];
warning(id, 'Read corrupt packet. Retrying...');
if brick.debug
fprintf('received (corrupt) (hex): [ ');
for ii=1:length(rmsg)
fprintf('%s ',dec2hex(rmsg(ii)))
end
fprintf(']\n');
fprintf('received (corrupt) (dec): [ ');
for ii=1:length(rmsg)
fprintf('%d ',rmsg(ii))
end
fprintf(']\n');
end
retries = 5;
while corrupt && retries
rmsg = brick.conn.read();
try
reply = Command(rmsg);
corrupt = 0;
catch
retries = retries-1;
end
end
end
if corrupt
rethrow(ME);
end
end
if reply.checkForError()
msg = 'Error byte is set. The Brick couldn''t handle the last packet';
id = [ID(), ':', 'CommandError'];
warning(id, msg);
end
% Verbose output
if brick.debug > 0
fprintf('received (hex): [ ');
for ii=1:length(rmsg)
......
......@@ -11,7 +11,7 @@
% - The read function should return a uint8 datatype
% - The write function should be given a uint8 datatype as a parameter
classdef BrickIO
classdef BrickIO < handle
properties (Abstract, Access = 'protected')
% connection handle
handle
......
......@@ -7,6 +7,13 @@ toolbox = 'RWTHMindstormsEV3';
stackTrace = dbstack();
% Element on top of stack is this function (ID()), second element is caller
% If no second element, caller is probably console -> not valid
if length(stackTrace) <= 1
ME = MException('RWTHMindstormsEV3:ID', ...
['ID() is only function on stack - can not create ID. (You can''t call ID() from ',...
'the console).']);
throw(ME);
end
callerList = strsplit(stackTrace(2).name, '.');
% The anticipated format of the caller is classname.functionname
......
......@@ -90,7 +90,11 @@ classdef btBrickIO < BrickIO
end
% Disconnect
brickIO.close;
try
brickIO.close;
catch
% Connection already closed (probably due to an error) - do nothing
end
end
function open(brickIO)
......@@ -108,9 +112,9 @@ classdef btBrickIO < BrickIO
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 = [ID(), ':', 'commError'];
% Throw only clean CommError to avoid confusion in upper layers
msg = 'Failed to open connection to Brick via Bluetooth.';
id = [ID(), ':', 'CommError'];
throw(MException(id, msg));
else
% Throw combined error because error did not happen due to communication
......@@ -165,12 +169,19 @@ classdef btBrickIO < BrickIO
% Read the remaining bytes
rmsg = fread(brickIO.handle,double(typecast(uint8(nLength),'uint16')));
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);
if strcmp(ME.identifier, 'MATLAB:serial:fread:opfailed')
% Throw only clean CommError to avoid confusion in upper layers
msg = 'Failed to read data from Brick via Bluetooth.';
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 reading data from the Brick via BT.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);b.bee
end
end
% Append the reply size to the return message
......@@ -195,13 +206,20 @@ classdef btBrickIO < BrickIO
% 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);
if strcmp(ME.identifier, 'MATLAB:serial:fwrite:opfailed')
% Throw only clean CommError to avoid confusion in upper layers
msg = 'Failed to send data to Brick via Bluetooth.';
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 sending data to the Brick via BT.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
throw(newException);
end
end
end
end
end
\ No newline at end of file
end
......@@ -124,8 +124,8 @@ classdef hidapi < handle
if isempty(findstr(ME.identifier, 'LoadFailed')) ...
&& isempty(findstr(ME.identifier, 'ErrorLoadingLibrary')) ...
&& isempty(findstr(ME.identifier, 'ErrorInHeader'))
id = [ID(), ':', 'InvalidParameterOrFileMissing'];
msg = 'Invalid parameters were given or files are not available.';
id = [ID(), ':', 'InvalidFileNameOrFileMissing'];
msg = 'Invalid file names were given or files are not available.';
cause = MException(id, msg);
exception = addCause(exception, cause);
end
......@@ -281,10 +281,24 @@ classdef hidapi < handle
% Read data from HID device
[res,h] = calllib(hid.slib,'hid_read',hid.handle,pbuffer,uint64(length(buffer)));
% (MMI) Check the response
assert(res>=1, ...
[ID(), ':', 'CommError'], ...
'Failed to read data via USB.');
% (MMI) Check the response (No assert as there are multiple cases)
if res < 1
% Error occurred
id = [ID(), ':', 'CommError'];
% Narrow error down
if res == -1
msg = 'Connection error (probably lost connection to device)';
elseif res == 0
msg = ['Could not read data from device (device is still connected, ',...
'but does not react)'];
else
msg = 'Unexpected connection error';
end
causeException = MException(id, msg);
ME = MException(id, 'Failed to read data via USB.');
addCause(ME, causeException);
throw(ME);
end
% Return the string value
rmsg = pbuffer.Value;
......
......@@ -98,7 +98,11 @@ classdef usbBrickIO < BrickIO
end
% Disconnect
brickIO.close;
try
brickIO.close;
catch
% Connection already closed (probably due to an error) - do nothing
end
end
function open(brickIO)
......@@ -145,7 +149,7 @@ classdef usbBrickIO < BrickIO
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.';
msg = 'Unknown error occurred while closing the USB connection.';
id = [ID(), ':', 'UnknownError'];
newException = MException(id, msg);
newException = addCause(newException, ME);
......@@ -191,29 +195,13 @@ classdef usbBrickIO < BrickIO
end
end
% (MMI) Sometimes, right after connecting via usb, the returned packets are of no
% recognized format. To avoid dealing with those for now, they are simply discarded
% and a new packet is requested.
% This workaround is NOT safe as you can see. It is just temporary and works most
% of the times.
for i=0:5
if rmsg(5) ~= 2 && rms(5) ~= 4
rmsg = brickIO.handle.read;
pause(0.005);
end
end
% Get the number of read bytes
nLength = double(typecast(uint8(rmsg(1:2)),'uint16'));
pLength = double(typecast(uint8(rmsg(1:2)),'uint16')) + 2;
% Format the read message (2 byte length plus message)
if nLength+2 < length(rmsg)
rmsg = rmsg(1:nLength+2);
else
warning([ID(), ':', 'CorruptPacket'], ...
'Returned packet''s length doesn''t equal its length indicator (bytes 1 & 2).');
if pLength < length(rmsg)
rmsg = rmsg(1:pLength);
end
end
function write(brickIO,wmsg)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment