function output = knauerpumpobjcomm(serialObject, type, command)
% KNAUERPUMPOBJCOMM Reads and writes data from Knauer pumps
% knauerpumpobjcomm(serialObject, type, command) reads from or writes
% information to Knauer pumps connected via RS232 serial ports.
% serialObject is the valid serial object, type is 'read' or 'write', and
% command the command to be sent (string). Automatically leaves a 0.15 s
% pause after any commands where there is no response expected to prevent
% communications issues. (PAUSE HAS NOT BEEN OPTIMISED)
% checks the number of arguments
error(nargchk(3, 3, nargin))
% error checking here
if ~isa(serialObject, 'serial') || ~isvalid(serialObject) || ~strcmp(serialObject.Status, 'open')
% the serial object must be valid and open to send or receive data
error('serialObject must be a valid open serial object.')
elseif ~isequal(type, 'read') && ~isequal(type, 'write')
% errors
error('type must be "read" or "write".')
elseif ~ischar(command) || ~isvector(command) || any(command == ' ')
% string must only be a single "word"
error('command must a string with no spaces.')
end
% sees if a colon has been specified
commandColonPosition = strfind(command, ':');
% if there's a colon in there then check there's a valid number after it
if ~isempty(commandColonPosition)
% if there's a colon, then you also can't put a ? at the end
if command(end) == '?'
% complain
error('If '':'' is present, then cannot have a ''?'' at the end of the command.')
end
% convert it to a number
commandNum = str2double(command(commandColonPosition + 1:end));
% checks that number is OK
if isempty(commandNum) || isnan(commandNum) || isinf(commandNum) || ~isreal(commandNum) || commandNum < 0 || commandNum ~= round(commandNum)
% complain
error('If a number is specified, it must be a valid positive integer.')
end
% if it got that far then define the commandWord for further checking
% later
commandWord = command(1:commandColonPosition - 1);
elseif command(end) == '?'
% if it was a read command, then return that, less the '?'
commandWord = command(1:end - 1);
else
% then it was neither of those, and the commandWord is the command
% as-is
commandWord = command;
end
% flushes everything in the buffer
fread(serialObject, serialObject.BytesAvailable);
% sends command
fprintf(serialObject, command, 'async')
% gets the response up to the terminator, discard it
response = fgetl(serialObject);
% if no response, then there was a problem
if isempty(response)
% error
error('No response to command.')
end
% now parse the response - find the location of the colon
responseColonPosition = strfind(response, ':');
% complain if it wasn't there
if isempty(responseColonPosition)
% complain
error('Unexpected response from Knauer pump - no '':''.')
else
% it's OK, so we can define the word that the instrument sent
responseWord = response(1:responseColonPosition - 1);
end
% if it was an error...
if strcmp(responseWord, 'ERROR')
% then say so
error(['Error response from Knauer pump - code ', response(responseColonPosition + 1:end)])
end
% check that it matched the initial command (case-insensitive check - the
% pump appears to be case insensitive)
if ~strcmpi(commandWord, responseWord)
% problem
error('Unexpected response from Knauer pump (''%s'') - does not match initial command.', response)
end
% if reading data, check the response
if strcmp(type, 'read')
% the number is nearly always just a number, but ERRORS returns the
% last five error codes as x,x,x,x,x so we need to cover that
% eventuality - most of the timer this is overkill but this
% futureproofs it
response = textscan(response(responseColonPosition + 1:end), '%f', 'Delimiter', ',');
% annoying formatting (thanks MATLAB) - turns it into a horizontal
% vector
output = response{1}';
elseif strcmp(type, 'write')
% need to check it was written... the response is command:OK if it was
if ~strcmp(response(responseColonPosition + 1:end), 'OK')
% error
error('Command was not written to pump - no OK was received.')
end
end