classdef FunctionGenerator < Equipment
%% FUNCTION_GENERATOR Control a function generator.
%	fg = FUNCTION_GENERATOR('IP', PORT, GPIB_CHAN) connects
%	to a function generator on IPv4 address 'IP', on port
%	'PORT' and GPIO channel 'GPIB_CHAN', using the Equipment
%	class.
%
%	See also EQUIPMENT, OSCILLOSCOPE, DIGITALMULTIMETER.
    
    properties (Dependent)
		%Dependent properties; stored on function generator,
		% read from or written to function generator when required.
		waveform
		frequency
		voltage
		unit
		offset
		load
    end
    
    methods
		function fg = FunctionGenerator(ipAddress,port,channel)
			%% FUNCTION_GENERATOR Control a function generator.
			%	fg = FUNCTION_GENERATOR('IP', PORT, GPIB_CHAN) connects
			%	to a function generator on IPv4 address 'IP', on port
			%	'PORT' and GPIO channel 'GPIB_CHAN', using the Equipment
			%	class.
			%
			%	See also EQUIPMENT, OSCILLOSCOPE, DIGITALMULTIMETER.
			fg@Equipment(ipAddress,port,channel);
		end

		function w = get.waveform(fg)
			%Get the function generator waveform setting on waveform
			% variable access, using the corresponding SCPI command.
			w = FunctionGenerator.getWave(fg.query('FUNCtion:SHAPe?'));
		end
		
		function f = get.frequency(fg)
			%Get function generator frequency setting on frequency variable
			% access, using the corresponding SCPI command.
			f = str2num(fg.query('FREQuency?'));
		end
		
		function v = get.voltage(fg)
			%Get function generator output voltage setting on output
			% variable access, using the corresponding SCPI command.
			v = str2num(fg.query('VOLTage?'));
		end

		function u = get.unit(fg)
			%Get function generator output voltage unit setting on offset
			% variable access, using the corresponding SCPI command.
			u = FunctionGenerator.getUnit(fg.query('VOLTage:UNIT?'));
		end

		function o = get.offset(fg)
			%Get function generator offset setting on offset variable
			% access, using the corresponding SCPI command.
			o = str2num(fg.query('VOLTage:OFFSet?'));
		end

		function l = get.load(fg)
			%Get function generator load setting on load variable
			% access, using the corresponding SCPI command.
			l = FunctionGenerator.getLoad(fg.query('OUTPut:LOAD?'));
		end

		function fg = set.waveform(fg,w)
			%Set function generator waveform setting on waveform variable
			% access, using the corresponding SCPI command.
			fg.write(['FUNCtion:SHAPe ' FunctionGenerator.getWave(w)]);
		end

		function fg = set.frequency(fg,f)
			%Set function generator frequency setting on frequency variable
			% access, using the corresponding SCPI command.
			Equipment.forceNum(f);
			fg.write(['FREQuency ' num2str(f)]);
		end

		function fg = set.voltage(fg,v)
			%Set function generator output voltage on voltage variable
			% access, using the corresponding SCPI command.
			Equipment.forceNum(v);
			fg.write(['VOLTage ' num2str(v)]);
		end

		function fg = set.unit(fg,u)
			%Set function generator output voltage unit setting on unit
			% variable access, using the corresponding SCPI command.
			fg.write(['VOLTage:UNIT ' FunctionGenerator.getUnit(u)]);
		end

		function fg = set.offset(fg,o)
			%Set function generator offset setting on offset variable access,
			% using the corresponding SCPI command.
			Equipment.forceNum(o);
			fg.write(['VOLTage:OFFSet ' num2str(o)]);
		end

		function fg = set.load(fg,l)
			%Set function generator load setting on load variable access,
			% using the corresponding SCPI command.
			fg.write(['OUTPut:LOAD ' FunctionGenerator.getLoad(l)]);
        end
    end

	methods (Static)
		function w = getWave(win)
			%GETWAVE Returns the waveform ('sinusoid', 'square', 'triangle',
			% 'ramp', 'noise', 'dc', 'user', 'minimum' or 'maximum') from
			% function generator output or (possibly malformed) user input.

			%Match two letter inputs first, single letters or single numbers
			% second. 's' is a special case (case sensitive for sine or Square).
			% Longer inputs are matched and reduced to two letters.
			w = regexp(num2str(win), '(si|sq|mi|ma|[trndu1-7]|s)', 'match', 'once', 'ignorecase');

			%Error if not matched.
			if isempty(w)
				error(['Invalid waveform: ' win]);
			end

			%Replace two letter, single letter or single number by correct
			% waveform.
			w = regexprep(w, {'^(1|si|(?-i)s)$', '^(2|sq|(?-i)S)$', '^[3t]$', '^[4r]$', '^[5n]$', '^[6d]$', '^[7u]$', '^mi$', '^ma$'}, ...
                {'sinusoid', 'square', 'triangle', 'ramp', 'noise', 'dc', 'user', 'minimum', 'maximum'}, 'ignorecase');
		end

		function u = getUnit(uin)
			%GETUNIT Returns the unit ('Vpp', 'Vrms', 'dBm' or 'default')
			% from function generator output or (possibly malformed) user
			% input.

			%Match correct single number or double letter inputs.
			% Longer inputs are matched and reduced to two letters.
			u = regexp(num2str(uin), '([1-4]|vp|vr|db|de)', 'match', 'once', 'ignorecase');

			%Error if not matched.
			if isempty(u)
				error(['Invalid voltage unit: ' uin]);
			end

			%Replace two letter or single number by correct unit.
			u = regexprep(u, {'^(1|vp)$', '^(2|vr)$', '^(3|db)$', '^(4|de)$'}, ...
                {'Vpp', 'Vrms', 'dBm', 'default'}, 'ignorecase');
		end

		function u = getLoad(lin)
			%GETLOAD Returns the load setting ('50', 'infinity', 'minimum',
			% or 'maximum') from function generator output or
			% (possibly malformed) user input.

			%Match correct number or double letter inputs.
			% Longer inputs are matched and reduced to two letters.
			l = regexp(num2str(lin), '([12]|50|in|mi|ma)', 'match', 'once', 'ignorecase');

			%Error if not matched.
			if isempty(l)
				error(['Invalid load: "' lin '".']);
			end

			%Replace two letter or single number by correct load setting.
			u = regexprep(l, {'^(1|50)$', '^(2|in)$', '^mi$', '^ma$'}, ...
                {'50', 'infinity', 'minimum', 'maximum'}, 'ignorecase');
		end
	end
    
end

