function pfcblock_utilParameterCheck(blk)
% Check mask dialog parameters for Path Following Control System Block.
%
%   Author: Meng Xia, Rong Chen

%   Copyright 2017-2018 The MathWorks, Inc.

%% get parameter values from mask workspace
maskWSVars = get_param(blk,'MaskWSVariables');
blkWSVarNames = {maskWSVars.Name};

% vehicle dynamics paras
m = maskWSVars(strcmp(blkWSVarNames,'VehicleMass')).Value;
Iz = maskWSVars(strcmp(blkWSVarNames,'VehicleYawInertia')).Value;
lf = maskWSVars(strcmp(blkWSVarNames,'LengthToFront')).Value;
lr = maskWSVars(strcmp(blkWSVarNames,'LengthToRear')).Value;
Cf = maskWSVars(strcmp(blkWSVarNames,'FrontTireStiffness')).Value;
Cr = maskWSVars(strcmp(blkWSVarNames,'RearTireStiffness')).Value;
lag = maskWSVars(strcmp(blkWSVarNames,'TransportLag')).Value;
tau = maskWSVars(strcmp(blkWSVarNames,'AccelTimeConstant')).Value;

% vehicle dynamics matrices
Av = maskWSVars(strcmp(blkWSVarNames,'EgoModelMatrixA')).Value;
Bv = maskWSVars(strcmp(blkWSVarNames,'EgoModelMatrixB')).Value;
Cv = maskWSVars(strcmp(blkWSVarNames,'EgoModelMatrixC')).Value;

% controller constraints
umax = maskWSVars(strcmp(blkWSVarNames,'MaxSteering')).Value;
umin = maskWSVars(strcmp(blkWSVarNames,'MinSteering')).Value;
amax = maskWSVars(strcmp(blkWSVarNames,'MaxAcceleration')).Value;
amin = maskWSVars(strcmp(blkWSVarNames,'MinAcceleration')).Value;

% mpc design paras
Ts = maskWSVars(strcmp(blkWSVarNames,'Ts')).Value;
psteps = maskWSVars(strcmp(blkWSVarNames,'PredictionHorizon')).Value;
ControlHorizon = maskWSVars(strcmp(blkWSVarNames,'ControlHorizon')).Value;
LateralWeight = maskWSVars(strcmp(blkWSVarNames,'LateralWeight')).Value;
LongWeight = maskWSVars(strcmp(blkWSVarNames,'LongWeight')).Value;
SteerWeight = maskWSVars(strcmp(blkWSVarNames,'SteerRateWeight')).Value;
AccelWeight = maskWSVars(strcmp(blkWSVarNames,'AccelRateWeight')).Value;

maxiter = maskWSVars(strcmp(blkWSVarNames,'maxiter')).Value;

% initial conditions
Vx0 = maskWSVars(strcmp(blkWSVarNames,'InitialLongVel')).Value;
L0 = maskWSVars(strcmp(blkWSVarNames,'DefaultSpacing')).Value;

%% get default status of checkboxes
umin_ext = strcmp(get_param(blk,'umin_ext'),'on');
umax_ext = strcmp(get_param(blk,'umax_ext'),'on');
amin_ext = strcmp(get_param(blk,'amin_ext'),'on');
amax_ext = strcmp(get_param(blk,'amax_ext'),'on');
suboptimal = strcmp(get_param(blk,'suboptimal'),'off');
hasSpacingCtrl = strcmp(get_param(blk,'spaceCtrl'),'on');

%% check parameters

%% check on system matrices
checkLinearModel(Av,Bv,Cv)

% check on vehicle paras: positive, finite, real, scalar
checkPositiveParam(m,getString(message('MPC:adasblocks:varnamePFCVehicleMass')))
checkPositiveParam(Iz,getString(message('MPC:adasblocks:varnamePFCVehicleInertia')))
checkPositiveParam(lf,getString(message('MPC:adasblocks:varnamePFCVehicleLengthToFront')))
checkPositiveParam(lr,getString(message('MPC:adasblocks:varnamePFCVehicleLengthToRear')))
checkPositiveParam(Cf,getString(message('MPC:adasblocks:varnamePFCVehicleFrontStiffness')))
checkPositiveParam(Cr,getString(message('MPC:adasblocks:varnamePFCVehicleRearStiffness')))
checkPositiveParam(tau,getString(message('MPC:adasblocks:varnamePFCVehicleAccelTimeConstant')))
checkNonnegativeParam(lag,getString(message('MPC:adasblocks:varnamePFCTransportLag')))

%% check controller constraints
% check on minimum steering angle umin: finite, real, scalar
if ~umin_ext && ~isempty(umin)
    checkFiniteParam(umin,getString(message('MPC:adasblocks:varnamePFCMinSteering')))
end

% check on maximum steering angle umax: finite, real, scalar
if ~umax_ext && ~isempty(umax)
    checkFiniteParam(umax,getString(message('MPC:adasblocks:varnamePFCMaxSteering')))
end

% check umin must be less than umax
if (~umax_ext && ~isempty(umax) && ~umin_ext && ~isempty(umin))
    checkLessThan(umin,umax,getString(message('MPC:adasblocks:varnamePFCMinSteering')),getString(message('MPC:adasblocks:varnamePFCMaxSteering')))
end

% check on minimum acceleration: finite, real, scalar
if ~amin_ext && ~isempty(amin)
    checkFiniteParam(amin,getString(message('MPC:adasblocks:varnamePFCMinAcceleration')))
end

% check on maximum acceleration: finite, real, scalar
if ~amax_ext && ~isempty(amax)
    checkFiniteParam(amax,getString(message('MPC:adasblocks:varnamePFCMaxAcceleration')))
end

% check umin must be less than umax
if (~amax_ext && ~isempty(amax) && ~amin_ext && ~isempty(amin))
    checkLessThan(amin,amax,getString(message('MPC:adasblocks:varnamePFCMinAcceleration')),getString(message('MPC:adasblocks:varnamePFCMaxAcceleration')))
end

%% mpc
% check on sampling time Ts: non-negative, finite, real, scalar
checkPositiveParam(Ts,getString(message('MPC:adasblocks:varnamePFCSampleTime')))

% check on prediction steps psteps: positive, finite, real, scalar
checkIntegerParam(psteps,getString(message('MPC:adasblocks:varnamePFCPSteps')))

% check on control horizon ControlHorizon: positive, finite, real, scalar
if isscalar(ControlHorizon)
    checkIntegerParam(ControlHorizon,getString(message('MPC:adasblocks:varnamePFCControlHorizon')))
    checkNoMoreThan(ControlHorizon,psteps,getString(message('MPC:adasblocks:varnamePFCControlHorizon')),getString(message('MPC:adasblocks:varnamePFCPSteps')))
elseif isvector(ControlHorizon) && numel(ControlHorizon)>1
    for ct = 1:numel(ControlHorizon)
        checkIntegerParam(ControlHorizon(ct),getString(message('MPC:adasblocks:varnamePFCVectorControlHorizonElement')))
    end
    checkNoMoreThan(sum(ControlHorizon),psteps,getString(message('MPC:adasblocks:varnamePFCVectorControlHorizon')),getString(message('MPC:adasblocks:varnamePFCPSteps')))
else
    error((message('MPC:adasblocks:errPFCControlHorizon')));
end


    

% check on weight ratio weightratio: between zero and one, finite, real, scalar
checkPositiveParam(LongWeight,getString(message('MPC:adasblocks:varnamePFCLongWeight')))
checkPositiveParam(LateralWeight,getString(message('MPC:adasblocks:varnamePFCLateralWeight')))
checkPositiveParam(AccelWeight,getString(message('MPC:adasblocks:varnamePFCAccelRateWeight')))
checkPositiveParam(SteerWeight,getString(message('MPC:adasblocks:varnamePFCSteerRateWeight')))


% check on maximum iteration number maxiter: positive, finite, real, scalar, integer
if ~suboptimal && ~isempty(maxiter)
    checkPositiveParam(maxiter,getString(message('MPC:adasblocks:varnamePFCMaxIter')))
end

%% initial conditions
% check on initial ego longitudinal velocity Vx0: non-negative, finite, real, scalar
checkPositiveParam(Vx0,getString(message('MPC:adasblocks:varnamePFCInitEgoVel')))

% check on default spacing L0: non-negative, finite, real, scalar
if hasSpacingCtrl && ~isempty(L0)
    checkNonnegativeParam(L0,getString(message('MPC:adasblocks:varnamePFCDefaultSpacing')))
end


%% local functions
% Local function: non-negative, finite, real, scalar
function checkNonnegativeParam(var,varname)
if ~(isnumeric(var) && isscalar(var) && isreal(var) && isfinite(var) && (var>=0))
    error((message('MPC:adasblocks:errPFCParamNonNegScalarFiniteReal',varname)));
end
   
% Local function: positive, finite, real, scalar
function checkPositiveParam(var,varname)
if ~(isnumeric(var) && isscalar(var) && isreal(var) && isfinite(var) && (var>0))
    error((message('MPC:adasblocks:errPFCParamPosScalarFiniteReal',varname)));
end  

% Local function: positive, finite, real, scalar, integer
function checkIntegerParam(var,varname)
if ~(isnumeric(var) && isscalar(var) && isreal(var) && isfinite(var) && (var>0) && isequal(round(var),var))
    error((message('MPC:adasblocks:errPFCParamPosScalarFiniteRealInteger',varname)));
end  

% Local function: less than
function checkLessThan(var1,var2,varname1,varname2)
if var1>=var2
    error((message('MPC:adasblocks:errPFCParamLessThan',varname1,varname2)));
end 

% Local function: no more than
function checkNoMoreThan(var1,var2,varname1,varname2)
if var1>var2
    error((message('MPC:adasblocks:errPFCParamNoMoreThan',varname1,varname2)));
end 

% Local function: finite, real, scalar
function checkFiniteParam(var,varname)
if ~(isnumeric(var) && isscalar(var) && isreal(var) && isfinite(var))
    error((message('MPC:adasblocks:errPFCParamScalarFiniteReal',varname)));
end 

% Local function: finite, real, scalar between min and max values
function checkInRangeParam(var,varname,varmin,varmax)
if ~(isnumeric(var) && isscalar(var) && isreal(var) && isfinite(var) && (var>=varmin) && (var<=varmax))
    error((message('MPC:adasblocks:errPFCParamRangeScalarFiniteReal',varname,num2str(varmin),num2str(varmax))));
end

% Local function: model has to be SISO and pass the mpc plant check (see mpcapp.util.checkPlant)
function checkLinearModel(A,B,C)
% number of states
NumStates = size(A,1);
% check matrices
if ~( ismatrix(A) && (size(A,2)==NumStates) && isreal(A) )
    error((message('MPC:adasblocks:errPFCEgoModelMatrixA')));
end
if ~( ismatrix(B) && isreal(B)  && isreal(B))
    error((message('MPC:adasblocks:errPFCEgoModelMatrixB')));
end
if ~( ismatrix(C) && isreal(C) && (size(C,1)==3) )
    error((message('MPC:adasblocks:errPFCEgoModelMatrixC')));
end
% check size mismatch
if ~( (size(B,1)==NumStates) && (size(C,2)==NumStates) )
    error((message('MPC:adasblocks:errPFCEgoModelMatrixSize')));
end
% check minimal realization
plant = ss(A,B,C,0);
sysr = minreal(plant);
if (size(sysr.A,1)~=NumStates)
    error((message('MPC:adasblocks:errPFCEgoModelMatrixMinimal')));
end





    
