function fprintf(obj, varargin)
%FPRINTF Write text to device.
%
%    FPRINTF(OBJ,'CMD') writes the string, CMD, to the device connected
%    to serial port object, OBJ. OBJ must be a 1-by-1 serial port object.
%
%    The serial port object must be connected to the device with the 
%    FOPEN function before any data can be written to the device otherwise
%    an error is returned. A connected serial port object has a Status
%    property value of open.
%
%    FPRINTF(OBJ,'FORMAT','CMD') writes the string CMD, to the device
%    connected to serial port object, OBJ, with the format, FORMAT. By
%    default, the %s\n FORMAT string is used. The SPRINTF function is 
%    used to format the data written to the instrument.
% 
%    Each occurrence of \n in CMD is replaced with OBJ's Terminator
%    property value. When using the default FORMAT, %s\n, all commands 
%    written to the device will end with the Terminator value.
%
%    FORMAT is a string containing C language conversion specifications. 
%    Conversion specifications involve the character % and the conversion 
%    characters d, i, o, u, x, X, f, e, E, g, G, c, and s. See the SPRINTF
%    file I/O format specifications or a C manual for complete details.
%
%    FPRINTF(OBJ, 'CMD', 'MODE')
%    FPRINTF(OBJ, 'FORMAT', 'CMD', 'MODE') writes data asynchronously
%    to the device when MODE is 'async' and writes data synchronously
%    to the device when MODE is 'sync'. By default, the data is written
%    with the 'sync' MODE, meaning control is returned to the MATLAB
%    command line after the specified data has been written to the device
%    or a timeout occurs. When the 'async' MODE is used, control is
%    returned to the MATLAB command line immediately after executing 
%    the FPRINTF function. 
%
%    OBJ's TransferStatus property will indicate if an asynchronous 
%    write is in progress.
%
%    OBJ's ValuesSent property will be updated by the number of values 
%    written to the device.
%
%    If OBJ's RecordStatus property is configured to on with the RECORD
%    function, the data written to the device will be recorded in the
%    file specified by OBJ's RecordName property value.
%
%    Example:
%      s = serial('COM1');
%      fopen(s);
%      fprintf(s, 'Freq 2000');
%      fclose(s);
%      delete(s);
%
%    See also SERIAL/FOPEN, SERIAL/FWRITE, SERIAL/STOPASYNC, SERIAL/RECORD,
%    SPRINTF.
%    

%    MP 7-13-99
%    Copyright 1999-2000 The MathWorks, Inc. 
%    $Revision: 1.4 $  $Date: 2000/08/29 23:47:50 $

% Error checking.
if ~isa(obj, 'instrument')
    error('OBJ must be a instrument object.');
end

if length(obj)>1
    error('OBJ must be a 1-by-1 instrument object.');
end

% Parse the input.
switch (nargin)
case 1
   error('CMD must be specified.');
case 2
   % Ex. fprintf(obj, cmd); 
   cmd = varargin{1};
   format = '%s\n';
   mode = 0;
case 3
   % Original assumption: fprintf(obj, format, cmd); 
   [format, cmd] = deal(varargin{1:2});
   mode = 0;
   if ~(isa(cmd, 'char') | isa(cmd, 'double'))
	   error('The third input argument must be a string.');
   end
   
   if strcmpi(cmd, 'sync') 
       % Actual: fprintf(obj, cmd, mode);
       mode = 0;
       cmd = format;
       format = '%s\n';
   elseif strcmpi(cmd, 'async') 
       % Actual: fprintf(obj, cmd, mode);
       mode = 1;
       cmd = format;
       format = '%s\n';
   end
case 4
   % Ex. fprintf(obj, format, cmd, mode); 
   [format, cmd, mode] = deal(varargin{1:3}); 
   
   if ~isstr(mode)
	   error('MODE must be either ''sync'' or ''async''.');
   end
   
   switch lower(mode)
   case 'sync'
       mode = 0;
   case 'async'
       mode = 1;
   otherwise
	   error('MODE must be either ''sync'' or ''async''.');
   end
otherwise
   error('Too many input arguments.');
end   

% Error checking.
if ~isa(format, 'char')
	error('FORMAT must be a string.');
end
if ~(isa(cmd, 'char') | isa(cmd, 'double'))
	error('CMD must be a string.');
end

% Parse and format the string.
[formattedCmd, errflag] = localParseString(format, cmd);
if errflag
    error(lasterr);
end

% Call the fprintf java method.
try
   fprintf(igetfield(obj, 'jobject'), formattedCmd, mode);
catch
   error(lasterr);
end   

% *********************************************************************
% Determine when the terminator is to be sent.
function [out, errflag] = localParseString(format, cmd)

% Initialize variables.
out       = {};
lastIndex = 1;
count     = 1;
errflag   = 0;

% The output will be a cell array.  Each element of the cell array is 
% a string to be written to the device.  The cells that contain a
% -1 will output the Terminating character as defined by the object.

% Format the string.
[h, errmsg] = sprintf(format, cmd);
if ~isempty(errmsg)
    errflag = 1;
    lasterr(errmsg);
    return;
end

h1 = real(h);

% Loop through the real formatted command and separate the carriage
% returns into their own cell as -1.
for i = 1:length(h1)
	switch (h1(i))
    case real(sprintf('\n'))
        % A carriage return in the formatted string was found.
        if lastIndex == i
            % No data that hasn't been assigned into a cell exists
            % before the carriage return.
            out{count} = -1;
            count = count+1;
            lastIndex = i+1;
        else
            % Data exists that hasn't been put into a cell before
            % the carriage return.
        	out{count} = h(lastIndex:i-1);
        	out{count+1} = -1;
   			count = count+2;
        	lastIndex = i+1;
        end
	case real('\')
        if h1(i+1) == real('n')
            % A \n was found (this occurs if the \n was placed in 
            % the command rather than the format.)
            if lastIndex == i
                % No data that hasn't been assigned into a cell exists
                % before the \n.
                out{count} = -1;
                count = count+1;
                lastIndex = i+2;
            else
                % Data exists that hasn't been put into a cell before
                % the \n.
		   		out{count} = h(lastIndex:i-1);
           		out{count+1} = -1;
           		count = count+2;
           		lastIndex = i+2;
            end
        end
    end
end

% If any data remains place into into a cell.
if lastIndex <= i
    out{count} = h(lastIndex:i);
end

