classdef Timer < handle
%TIMER supports execution time profiling on target hardware

%   Copyright 2009-2012 The MathWorks, Inc.

    properties(SetAccess = 'private' , GetAccess = 'public')
        TimerDataType; % data type returned by the timer function.
        TicksPerSecond; 
        HeaderFile; % header file to be included
        SourceFile; % timer source file
        ReadTimerExpression; % function or expression to read timer
        CountDirection = 'up'; % "up" if timer increments or "down" if it decrements
        LinkFlags = {}; % Used to provide library dependencies, e.g.: { '-lrt' }
        Defines = {}; % Used to pass defines to the compiler, e.g.: to enable/disable features
    end
    
    properties (Constant = true, GetAccess = 'private')
        ValidDataTypes = {'uint8', 'uint16', 'uint32', 'uint64'};
        
    end
    
    methods
        % constructor
        function this = Timer(arg1DoNotUse, arg2DoNotUse,...
                              arg3DoNotUse, arg4DoNotUse,...
                              arg5DoNotUse, ~)

            if nargin > 0
                % Note that the use of constructor arguments is deprecated (g662080).
                % For backwards compatibility, allow arguments to be passed 
                % to the constructor. It is recommended to call the constructor
                % with no arguments then invoke the set methods on the instantiated 
                % object.
                this.setTimerDataType(arg1DoNotUse);                                       
                this.setSourceFile(arg2DoNotUse);
                this.setTicksPerSecond(arg3DoNotUse);
                this.setReadTimerExpression(arg4DoNotUse);
                this.setHeaderFile(arg5DoNotUse);
            end
            
        end
    end
    
    methods (Sealed = true)

        % get the data type 
        function timerDataType = getDataType(this)
            narginchk(1, 1);
            timerDataType = this.TimerDataType;
            if isempty(timerDataType)
                DAStudio.error('CoderProfile:ExecutionTime:ConnectivityConfigTimerIncomplete',...
                               'setTimerDataType');
            end
        end
        
        % get number of seconds per clock tick
        function ticksPerSecond = getTicksPerSecond(this)
            narginchk(1, 1);
            ticksPerSecond = this.TicksPerSecond;
        end
        
        
        
        function setSourceFile(this, timerSourceFile)
            
            narginchk(2, 2);
            
            this.SourceFile = timerSourceFile;
            
        end
            
        
        function setReadTimerExpression(this, readTimer)
            
            narginchk(2, 2);
            
            this.ReadTimerExpression = readTimer;
            
        end
            
        function timerReadExpr = getReadTimerExpression(this)
            
            timerReadExpr = this.ReadTimerExpression;
            
            if isempty(timerReadExpr)
                DAStudio.error('CoderProfile:ExecutionTime:ConnectivityConfigTimerIncomplete',...
                               'setReadTimerExpression');
            end
            
        end
            
        function setHeaderFile(this, timerHeaderFile)
            
            narginchk(2, 2);
            
            this.HeaderFile = timerHeaderFile;
            
        end
            
        function setTimerDataType(this, timerDataType)
            
            narginchk(2, 2);
            
            % strip any trailing "_T" (backwards compatibility)
            if strcmp(timerDataType(end-1:end),'_T')
                timerDataType=timerDataType(1:end-2);
            end
            
            validTypes =  coder.profile.Timer.ValidDataTypes;
            
            if ~any(strcmp(timerDataType, validTypes))
                formattedValidTypes = sprintf('%s, ', validTypes{:});
                formattedValidTypes = formattedValidTypes(1:end-2);
                DAStudio.error('CoderProfile:ExecutionTime:InvalidTimerDataTypeBackwardsCompat',...
                               timerDataType, formattedValidTypes);
            end

            this.TimerDataType = timerDataType;
        end

        
        % set number of seconds per clock tick
        function setTicksPerSecond(this, ticksPerSecond)
            
            narginchk(2, 2);
            if ~isempty(ticksPerSecond)
                validateattributes(ticksPerSecond,...
                    {'double'},...
                    {'positive','real','scalar'}, ...
                    'coder.profile.Timer',...
                    'ticksPerSecond',...
                    2);
            end
            this.TicksPerSecond = ticksPerSecond;
        end
        
        
        % set the timer count direction
        function setCountDirection(this, countDirection)
            
            narginchk(2, 2);
            if ~ischar(countDirection) || ...
                    ~any(strcmp({'up','down'},countDirection))
                DAStudio.error('CoderProfile:ExecutionTime:InvalidTimerCountDirection');
            end

            this.CountDirection = countDirection;
        end
        
        % set the link flags (which will be passed to the compiler during
        % the link stage). You can provide external library dependencies
        % here, for example: { '-lrt' }
        function setLinkFlags(this, linkFlags)
            % Validate input
            narginchk(2, 2);
            validateattributes(linkFlags, ...
                {'cell'}, {'vector'}, ...
                'coder.profile.Timer.setLinkFlags', ...
                'linkFlags', 2);
            
            this.LinkFlags = linkFlags;
        end
        
        % sets the compile defines (which will be passed to the compiler
        % during the compile stage). This can be used to enable/disable
        % compile-time features.
        %
        % This function takes a cell array of strings as an argument.
        function setDefines(this, defines)
            % Validate input
            narginchk(2, 2);
            validateattributes(defines, ...
                {'cell'}, {'vector'}, ...
                'coder.profile.Timer.setDefines', ...
                'defines', 2);
            
            this.Defines = defines;
        end
        
    end
end

