function slpidlevel2msfunc(block)
% Level 2 M S-Function used to tune PID controller when the tuning module
% is not deployed on the hardware.

%   Author: R. Chen
%   Copyright 2016-2017 The MathWorks, Inc.

%%
%% The setup method is used to set up the basic attributes of the
%% S-function such as ports, parameters, etc. Do not add any other
%% calls to the main body of the function.
%%
setup(block);

%endfunction

%% Function: setup ===================================================
%% Abstract:
%%   Set up the basic characteristics of the S-function block such as:
%%   - Input ports
%%   - Output ports
%%   - Dialog parameters
%%   - Options
%%
%%   Required         : Yes
%%   C-Mex counterpart: mdlInitializeSizes
%%
function setup(block)

% Register number of ports
block.NumInputPorts  = 1;
block.NumOutputPorts = 0;

% Setup port properties to be inherited or dynamic
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;

% Override input port properties
block.InputPort(1).Dimensions  = 1;
block.InputPort(1).Complexity  = 'Real';
block.InputPort(1).DirectFeedthrough = true;

% Register parameters
block.NumDialogPrms  = 0;

% Register sample times
%  [0 offset]            : Continuous sample time
%  [positive_num offset] : Discrete sample time
%
%  [-1, 0]               : Inherited sample time
%  [-2, 0]               : Variable sample time
block.SampleTimes = [-1 0];

% Specify the block simStateCompliance. The allowed values are:
%    'UnknownSimState', < The default setting; warn and assume DefaultSimState
%    'DefaultSimState', < Same sim state as a built-in block
%    'HasNoSimState',   < No sim state
%    'CustomSimState',  < Has GetSimState and SetSimState methods
%    'DisallowSimState' < Error out when saving or restoring the model sim state
block.SimStateCompliance = 'DefaultSimState';

% -------------------------------------------------------------------------
% Make sure this only is used as a viewing device and doesn't generate Code
block.SetSimViewingDevice(true); 
% -------------------------------------------------------------------------

%% -----------------------------------------------------------------
%% The MATLAB S-function uses an internal registry for all
%% block methods. You should register all relevant methods
%% (optional and required) as illustrated below. You may choose
%% any suitable name for the methods and implement these methods
%% as local functions within the same file. See comments
%% provided for each function for more information.
%% -----------------------------------------------------------------
block.RegBlockMethod('Start', @Start);
block.RegBlockMethod('Outputs', @Outputs);     % Required
block.RegBlockMethod('Update', @Update);
block.RegBlockMethod('Terminate', @Terminate); % Required
block.RegBlockMethod('PostPropagationSetup', @DoPostPropSetup);
block.RegBlockMethod('InitializeConditions', @InitializeConditions);
%end setup

function DoPostPropSetup(block)
%% set up states
block.NumDworks = 6;
block.Dwork(1).Name            = 'PP';
block.Dwork(2).Name            = 'II';
block.Dwork(3).Name            = 'DD';
block.Dwork(4).Name            = 'NN';
block.Dwork(5).Name            = 'PM';
block.Dwork(6).Name            = 'LastStartStop'; % previously monitored
for ct=1:6
    block.Dwork(ct).Dimensions      = 1;
    block.Dwork(ct).DatatypeID      = 0;
    block.Dwork(ct).Complexity      = 'Real'; 
    block.Dwork(ct).UsedAsDiscState = true;
end
%end DoPostPropSetup

function InitializeConditions(block)
%% Initialize Dwork
block.Dwork(1).Data = 0;
block.Dwork(2).Data = 0;
block.Dwork(3).Data = 0;
block.Dwork(4).Data = 100;
block.Dwork(5).Data = 60;
block.Dwork(6).Data = -1; % must initialize with a negative value
%end InitializeConditions

%%
%% Start:
%%   Functionality    : Called once at start of model execution. If you
%%                      have states that should be initialized once, this 
%%                      is the place to do it.
%%   Required         : No
%%   C-MEX counterpart: mdlStart
%%
function Start(~)
%end Start

%%
%% Outputs:
%%   Functionality    : Called to generate block outputs in
%%                      simulation step
%%   Required         : Yes
%%   C-MEX counterpart: mdlOutputs
%%
function Outputs(~)
%end Outputs

%%
%% Update:
%%   Functionality    : Called to update discrete states
%%                      during simulation step
%%   Required         : No
%%   C-MEX counterpart: mdlUpdate
%%
function Update(block)
if (block.InputPort(1).Data<=0) && (block.Dwork(6).Data>0)
    % detect falling edge of start/stop signal to trigger one-shot tuning
    tunerblk = get_param(block.BlockHandle,'Parent');
    slpidwrapperMSFunc(tunerblk);   
end
block.Dwork(6).Data = double(block.InputPort(1).Data);
%end Update

%%
%% Terminate:
%%   Functionality    : Called at the end of simulation for cleanup
%%   Required         : Yes
%%   C-MEX counterpart: mdlTerminate
%%
function Terminate(~)
%end Terminate

