function varargout = commblkconvcod2(action, blkh, varargin)
% COMMBLKCONVCOD2 Communications Toolbox Convolutional Encoder block
% mask helper function.

%   Copyright 1996-2022 The MathWorks, Inc.

switch action
    case 'init'

        cbOpMode(blkh);
        cbIsPunctured(blkh);

        ArgTrellis        = varargin{1}; % unchanged

        ArgReset          = varargin{2};
        switch ArgReset  % for old reset param values
            % Set OpMode and then set reset to the unused value
            case 2
                set_param(blkh, 'opMode', 'Continuous');
                set_param(blkh, 'reset', 'Unused parameter value');
            case 3
                set_param(blkh, 'opMode', 'Truncated (reset every frame)');
                set_param(blkh, 'reset', 'Unused parameter value');
            case 4
                set_param(blkh, 'opMode', 'Reset on nonzero input via port');
                set_param(blkh, 'reset', 'Unused parameter value');
        end
        ArgIniStPort = varargin{3};
        ArgFinStPort = varargin{4};

        % Use ArgOpMode from now
        ArgOpMode = get_param(blkh, 'OpMode');
        s = initWorkSpace(ArgOpMode, ArgIniStPort, ArgFinStPort);

        % Do not evaluate/check the parameters if the simulation status is 'stopped'.
        % This is the case when loading a model with the block in it.
        simStat = get_param(bdroot(blkh),'SimulationStatus');
        if (~strcmpi(simStat,'stopped'))
            % Check trellis structure and update workspace return struct
            s = updateWorkSpace(s, ArgTrellis);
        end

        varargout{1} = s;

    case 'cbOpMode'
        cbOpMode(blkh);
        varargout = {};
    case 'cbIsPunctured'
        cbIsPunctured(blkh);
        varargout = {};
end

function s = initWorkSpace(ArgOpMode, ArgIniStPort, ArgFinStPort)
% initWorkSpace: Create a workspace structure

s            = [];
s.k          = [];
s.n          = [];
s.numStates  = [];
s.outputs    = [];
s.nextStates = [];
s.hasIniStPort = 0;
s.hasFinStPort = 0;
s.hasRstPort = 0;
switch ArgOpMode  % convert to a literal
    case 'Continuous'
        s.opMode      = 1;
        s.hasFinStPort = ArgFinStPort;
    case 'Truncated (reset every frame)'
        s.opMode      = 2;
        s.hasIniStPort = ArgIniStPort;
        s.hasFinStPort = ArgFinStPort;
    case 'Terminate trellis by appending bits'
        s.opMode      = 3;
    case 'Reset on nonzero input via port'
        s.opMode      = 4;
        s.hasRstPort  = 1;
        s.hasFinStPort = ArgFinStPort;
end
s.status     = '';

% Input port labels
if ( (s.hasRstPort == 1) && (s.hasIniStPort == 0) )
    % Two input ports (no iniState port)
    s.i1 = 1; s.i1s = 'In';
    s.i2 = 2; s.i2s = 'Rst';
elseif ( (s.hasRstPort == 0) && (s.hasIniStPort == 1) )
    % Two input ports (no reset input port)
    s.i1 = 1; s.i1s = 'In';
    s.i2 = 2; s.i2s = 'ISt';
else
    % One input port only
    s.i1 = 1; s.i1s = '';
    s.i2 = 1; s.i2s = '';
end

% Output port labels
s.o1 = 1; s.o1s = '';
if (s.hasFinStPort == 1)
    s.o2 = 2; s.o2s = 'FSt';
else
    s.o2 = 1; s.o2s = '';
end

function s = updateWorkSpace(s, trellis)
% updateWorkSpace: add trellis information to workspace structure

[isOk, msg] = istrellis(trellis);
if ~isOk
    s.id     = 'comm:commblkconvcod2:InvalidTrellis';
    s.status = ['Invalid trellis structure.' msg];
    return;
end

% Set block parameters
s.k          = log2(trellis.numInputSymbols);
s.n          = log2(trellis.numOutputSymbols);
s.numStates  = trellis.numStates;
s.outputs    = oct2dec(trellis.outputs);
s.nextStates = trellis.nextStates;
  
function cbOpMode(blkh)

if strcmp(get_param(blkh,'opMode'),'Terminate trellis by appending bits')
    % Hide the 'Output final state' check box
    % Hide the 'Puncture vector' check box
    hasFinStPortEn    = 'off'; % mask parameter (not mask object property)
    hasFinStPortVis   = 'off'; % mask parameter (not mask object property)
    usePuncVectorEn   = 'off'; % mask parameter (not mask object property)
    usePuncVectorVis  = 'off'; % mask parameter (not mask object property)
    punctureVectorEn  = 'off'; % also shut off the vector
    punctureVectorVis = 'off';
else
    hasFinStPortEn   = 'on';
    hasFinStPortVis  = 'on';
    usePuncVectorEn  = 'on';
    usePuncVectorVis = 'on';
    if strcmp(get_param(blkh,'usePuncVector'),'on')
        % Show the 'Puncture vector' edit box
        punctureVectorEn    = 'on'; % mask parameter (not mask object property)
        punctureVectorVis   = 'on'; % mask parameter (not mask object property)
    else
        punctureVectorEn    = 'off';
        punctureVectorVis   = 'off';
    end
end
if strcmp(get_param(blkh,'opMode'),'Truncated (reset every frame)')
    % Show the 'Specify initial state via input port' check box 
    hasIniStPortEn  = 'on'; % mask parameter (not mask object property)
    hasIniStPortVis = 'on'; % mask parameter (not mask object property)
else 
    hasIniStPortEn  = 'off';
    hasIniStPortVis = 'off';
end
if strcmp(get_param(blkh,'opMode'),'Reset on nonzero input via port')
    % Show the 'Delay reset action to next time step' check box
    delayedResetActionEn  = 'on'; % mask parameter (not mask object property)
    delayedResetActionVis = 'on'; % mask parameter (not mask object property)
else
    delayedResetActionEn  = 'off';
    delayedResetActionVis = 'off';
end

% Update mask parameter enables and visibilities if necessary
maskParamNames = get_param(blkh,'MaskNames');
mask_en_old    = get_param(blkh,'MaskEnables');
mask_en_new    = mask_en_old;
mask_vis_old   = get_param(blkh,'MaskVisibilities');
mask_vis_new   = mask_vis_old;

mask_en_new{strcmp(maskParamNames,'hasFinStPort')}         = hasFinStPortEn;
mask_vis_new{strcmp(maskParamNames,'hasFinStPort')}        = hasFinStPortVis;
mask_en_new{strcmp(maskParamNames,'usePuncVector')}        = usePuncVectorEn;
mask_vis_new{strcmp(maskParamNames,'usePuncVector')}       = usePuncVectorVis;
mask_en_new{strcmp(maskParamNames,'punctureVector')}       = punctureVectorEn;
mask_vis_new{strcmp(maskParamNames,'punctureVector')}      = punctureVectorVis;
mask_en_new{strcmp(maskParamNames,'hasIniStPort')}         = hasIniStPortEn;
mask_vis_new{strcmp(maskParamNames,'hasIniStPort')}        = hasIniStPortVis;    
mask_en_new{strcmp(maskParamNames,'DelayedResetAction')}   = delayedResetActionEn;
mask_vis_new{strcmp(maskParamNames,'DelayedResetAction')}  = delayedResetActionVis;

if ~isequal(mask_vis_old,mask_vis_new)
   set_param(blkh,'MaskEnables',mask_en_new,'MaskVisibilities',mask_vis_new);
end

function cbIsPunctured(blkh)

convEncMaskObj = Simulink.Mask.get(blkh);
% Property dialog UI controls
PunctureVectorBlankColumnLabel = ...
    convEncMaskObj.getDialogControl('PunctureVectorBlankColumnLabel');

if strcmp(get_param(blkh,'usePuncVector'),'on')
    % Show the 'Puncture vector' edit box
    punctureVectorEn                       = 'on'; % mask parameter (not mask object property)
    punctureVectorVis                      = 'on'; % mask parameter (not mask object property)
    PunctureVectorBlankColumnLabel.Enabled = 'on';
    PunctureVectorBlankColumnLabel.Visible = 'on';
else
    punctureVectorEn                       = 'off';
    punctureVectorVis                      = 'off';
    PunctureVectorBlankColumnLabel.Enabled = 'off';
    PunctureVectorBlankColumnLabel.Visible = 'off';
end

% Update mask parameter enables and visibilities if necessary
maskParamNames = get_param(blkh,'MaskNames');
mask_en_old    = get_param(blkh,'MaskEnables');
mask_en_new    = mask_en_old;
mask_vis_old   = get_param(blkh,'MaskVisibilities');
mask_vis_new   = mask_vis_old;

mask_en_new{strcmp(maskParamNames,'punctureVector')}   = punctureVectorEn;
mask_vis_new{strcmp(maskParamNames,'punctureVector')}  = punctureVectorVis;

if ~isequal(mask_vis_old,mask_vis_new)
   set_param(blkh,'MaskEnables',mask_en_new,...
                  'MaskVisibilities',mask_vis_new);
end

% [EOF]
