%% Global entry point
function hdlToolStrip( fcnname, varargin)
%HDLTOOLSTRIP - Handles HDL coder toolstrip actions

%   Copyright 2017-2023 The MathWorks, Inc.
    fnc = str2func( fcnname );
    fnc(varargin{:});
end

%% Refreshers
function buildConvertRF_HDL(userdata, cbinfo, action)
% sync enabled state with system selector
    SLStudio.toolstrip.internal.buildConvertRF(userdata, cbinfo, action);
    checkReferenceHierarchy(cbinfo, action)
end

function HDLCoderBlockPropsRF(cbinfo, action) %#ok<*DEFNU>
% Control enabled behavior of HDL Block Properties button
    if isSelectionValidHDLBlock(cbinfo)
        action.enabled = true;
    end
end

function systemSelectorRF_HDL(userdata, cbinfo, action)
% Wrap the System Selector refresher with extra logic to pull system
% information from config params
    SLStudio.toolstrip.internal.systemSelectorRF(userdata, cbinfo, action);
    checkReferenceHierarchy(cbinfo, action)
    if action.selected && hasHDLConfig(cbinfo)
        % system is currently pinned, make sure it is synchronized with the
        % config set
        hdlSystem = hdlget_param(cbinfo.model.Name, 'HDLSubsystem');
        if ~action.description.isequal(slservices.StringOrID(hdlSystem))
            insertPinnedSystem(hdlSystem, cbinfo, action);
            if ~action.description.isequal(slservices.StringOrID(hdlSystem))
                % if HDL Subsystem was not propagated to system selector,
                % then the SL object was either changed or the entered HDL
                % Subsystem is invalid
                % Copy the system selector information into the HDL
                % Subsystem to keep things synchronized
                hdlset_param(cbinfo.model.Name, 'HDLSubsystem', getSelectedSystem(cbinfo))
            end
        end
    end
end

function HDLCoderTraceCodeRF(cbinfo, action) %#ok<*DEFNU>
% Control enabled behavior of HDL Block Properties button
    modelName = get_param(cbinfo.Context.StudioApp.blockDiagramHandle,'Name');
    if isSelectionValidHDLBlock(cbinfo) && ...
            coder.internal.slcoderReport('enableHighlightHDLCodeMenu', modelName) % if traceability report is available
        if ~action.enabled %avoid updating flag if unnecessary
            action.enabled = true;
        end
    else
        action.enabled = false;
    end
end

function HDLTestbenchRF(userdata, cbinfo, action)
% check if system is top level of the model for testbench generation
    if isIPCoreGenerationWorkflow(cbinfo)
        % Disable testbench generation for IP core workflow
        action.enabled = false;
        return;
    end

    [~, ~, selectedSystem] = getSelectedSystem(cbinfo);
    if isa(selectedSystem, 'Simulink.BlockDiagram')
        % testbench generation not supported at top level of model
        action.enabled = false;
    else
        % continue on calling general refresher for system selector related
        % actions
        buildConvertRF_HDL(userdata, cbinfo, action);
    end
end

function HDLCoderVerifyRF(~, action)
% verify if HDL Verifier is installed
    persistent hasHDLVerifierLicense;
    if isempty(hasHDLVerifierLicense)
        % Check HDL Verifier license
        tooldir = fullfile(matlabroot, 'toolbox', 'hdlverifier');
        hasHDLVerifierLicense = license('test', 'EDA_Simulator_Link') && exist(tooldir, 'dir');
        % enable if license and install are valid
        action.enabled = hasHDLVerifierLicense;
    elseif action.enabled ~= hasHDLVerifierLicense
        % don't continue to check for license after the first time
        action.enabled = hasHDLVerifierLicense;
    end
end

function OpenHDLRptRF(cbinfo, action)
% refresher to enable/disable the HDL Report button
    rptPath = hdlcoder.report.ReportInfo.getSavedRptPath(cbinfo.model.Name, false);
    % only enable if a HDL check report has been generated and the file
    % still exists
    % if the check report exists, then a code generation report may also
    % exist
    action.enabled = ~isempty(rptPath) && exist(rptPath, 'file');
end

function SelectHostTargetInterfaceRF(userdata, cbinfo, action)
    % enables/disables the appropriate radio button in the
    % footer dropdown of the Verify menu in the IP Core context
    hostTargetInterface = getHostTargetInterface(cbinfo);
    action.selected = strcmp( userdata, hostTargetInterface );
end

function SwitchHostTargetInterfaceRF(cbinfo, action)
    %Switches the text on the footer dropdown of the Verify menu in the IP Core
    %context to reflect the value set in the downstream integration
    %driver
    if action.enabled && hdlwa.isWorkflowAdvisorOpenForModel(cbinfo.model.name) 
        %disable footer host interface script dropdown when HDL Workflow advisor is open
        action.enabled = false;
    else
        action.enabled = true;
    end
    hostTargetInterface = getHostTargetInterface(cbinfo);

    % select the text for each choice. (JTAG corresponds to "JTAG AXI Manager")
    if(strcmp(hostTargetInterface,'Ethernet'))
        action.text = 'Ethernet';
    else
        action.text = 'JTAG';
    end
end
%% Callbacks
function toggleHDLAppCB(userdata, cbinfo)
% callback for when HDL app is selected in app gallery
% Set system selector in pinned state when app is opened after being closed
% and a HDL System exists in the config params
    contextManager = cbinfo.studio.App.getAppContextManager;
    customContext = contextManager.getCustomContext(userdata);
    isAppPreviouslyOpen = ~isempty(customContext);

    if ~isAppPreviouslyOpen
        % open new HDL tab
        c = dig.Configuration.get();
        app = c.getApp(userdata);
        contextProvider = app.contextProvider;
        customContext = feval( contextProvider, app, cbinfo);
        contextManager.activateApp(customContext)
        
        % launch minimized code view
        if strcmp(hdlfeature('HDLCodeView'), 'on') && isempty(customContext.hdlCodeView)
            customContext.hdlCodeView = simulinkcoder.internal.CodeView_HDL(cbinfo.studio);
            customContext.hdlCodeView.open('',false);
        end        
        % set system selector to pinned state so it reflects the HDL system
        % in the config params with the HDL Toolstrip is opened after being
        % closed
        % The system selector refresher will handle updating the value
        updatePinnedSystem(cbinfo);
    elseif isempty(cbinfo.EventData) || cbinfo.EventData
        % HDL app button was clicked while tab was open, bring to focus
        ts = cbinfo.studio.getToolStrip;
        ts.ActiveTab = customContext.DefaultTabName;
    else
        % HDL app is closing, remove listeners to prevent memory leaks
        customContext.BDListener = [];
        customContext.CSListener = [];
        customContext.HDLPIListener = [];

        
        if strcmp(hdlfeature('HDLCodeView'), 'on')
            hdlcv = customContext.hdlCodeView;
            if ~isempty(hdlcv)
                hdlcv.close();
            end
            customContext.hdlCodeView = [];
        end
        contextManager.deactivateApp(userdata)
        % Close IP Core Settings UI and deployment settings UI if open when closing HDL coder app
        closeAllIPCoreUIs(cbinfo);        
    end
end

function ChangeOutputCB(userdata, cbinfo)
    % update output to generic HDL or generic IP Core
    model = cbinfo.model.name;

    switch userdata
        case "genericHDL"
            workflow = 'Generic ASIC/FPGA';
        case "genericIP"
            workflow = 'IP Core Generation';
        otherwise
            error("Unexpected workflow.");
    end

    % Set workflow on model
    hdlset_param(model, 'Workflow', workflow);

    % Launch IP core UI if we are switching into IP core workflow
    if isIPCoreGenerationWorkflow(cbinfo)
        openIPCoreUI(cbinfo);
    end
end

function OpenHDLLIBCB(~)
% hdl block library callback
    isHDLLIBOn = privhdllib_library_browser('checkState');
    
    if(isHDLLIBOn)
        % hdl library browser view is already generated, open it
        slLibraryBrowser;
    else
        % generate hdl library browser view and open it
        hdllib;
    end
end

function OpenHDLCoderOptionsCB(userdata, cbinfo)
% HDL options and report options callback
if nargin < 2
    % called without userdata, only cbinfo was passed in but it is
    % currently held in userdata variable
    cbinfo = userdata;
    userdata = '';
end

mdlName = cbinfo.model.Name;
sectionName = DAStudio.message('HDLShared:hdldialog:hdlccHDLCodername');
if ~isempty(userdata)
    % open a subsection of the HDL settings
    sectionName = [sectionName '/' DAStudio.message(userdata)];
end

hcc = gethdlcc(mdlName);
if ~isempty(hcc)
    hcc.createCLI;
    configset.showParameterGroup(mdlName, {sectionName});
end
end

function systemSelectorCB_HDL(~, cbinfo)
% Wrapper for systemSelectorCB to catch pin press
    if cbinfo.EventData
        % A system has been pinned
        % Check if it is a new valid system and set the system in the
        % config params if so
        mdlName = cbinfo.model.Name;
        currCPSystem = hdlget_param(mdlName, 'HDLSubsystem');
        selectedSystem = getSelectedSystem(cbinfo);
        if ~strcmp(currCPSystem, selectedSystem)
            % System was updated in toolstrip
            hdlset_param(mdlName, 'HDLSubsystem', selectedSystem);
        end
    end
end

function GenerateHDLCB(cbinfo)
% makehdl callback

    % the diagnostic viewer stage is created a new for evey run
    Simulink.output.Stage('HDLCoder', 'ModelName', cbinfo.model.Name, 'UIMode', true);
    % open diagnostic viewer stage 
    downstream.tool.openDiagnosticViewer(cbinfo.model.Name);
    runWorkflow('makehdl', cbinfo);
end

function GenerateIPCoreCB(cbinfo)
    % Generate IP core callback
    model = cbinfo.model.name;
    
    % TODO: Can we unify this entire function with hdlcoder.runWorkflow?

    % Get taskName for DV stage
    taskName = message('hdlcoder:toolstrip:GenerateIPHdlCoderActionText').getString;
    taskName = replace(taskName, newline, ' ');

    validateWorkflowAdvisorAndConfigsetStatus(model, taskName);

    % setUIsCodegenInProgress to true and cleaning up when done 
    setUIsCodegenInProgress(cbinfo, true);
    UIEnable = onCleanup(@() setUIsCodegenInProgress(cbinfo, false));

    % Run IP core generation
    runIPCoreGeneration(model);
end

function WorkflowAdvisorCB(cbinfo)
% hdl workflow advisor callback
    
    [~, ~, ~, isPinned] = getSelectedSystem(cbinfo);
    if isPinned
        % run WFA on the pinned system
        runWorkflow('hdladvisor', cbinfo);
    else
        % open the system selector for the WFA on the model
        hdladvisor(cbinfo.model.name, 'SystemSelector');
    end
end

function ModelAdvisorCB(cbinfo)
% hdl model advisor callback
    systemPath = getSelectedSystem(cbinfo);

    hdlmodelchecker(systemPath);
end

function HDLConfigAttachmentCB(cbinfo)
% hdl configuration callback
    hdlcodermenus('HDLC_AddHDLCoderCB', cbinfo);
    updatePinnedSystem(cbinfo);
end

function HDLConfigDetachmentCB(cbinfo)
% hdl configuration callback
    hdlcodermenus('HDLC_RemoveHDLCoderCB', cbinfo);
% Close IP Core Settings UI and deployment settings UI if open when
% clicking on remove HDL configuration
    closeAllIPCoreUIs(cbinfo);
end

function GenerateHDLTBCB(cbinfo)
% makehdltb callback
    
    pv_args = {...
        'GenerateHDLTestBench', 'on', ...
        'GenerateCoSimModel', 'none', ...
        'GenerateSVDPITestBench', 'none'...
        };
    
    if isCallFromToolstrip(cbinfo)
        runWorkflow('makehdltb', cbinfo, pv_args);
    else % dont' set any PV pairs for legacy callback
        runWorkflow('makehdltb', cbinfo);
    end
end

function GenerateHDLCosimCB(cbinfo)
% makehdltb with cosim callback
% get tool info, massage to acceptable CLI name
    tool = getHDLSimTool(cbinfo.model.Name);
    
    pv_args = {...
        'GenerateHDLTestBench', 'off', ...
        'GenerateCoSimModel', tool, ...
        'GenerateSVDPITestBench', 'none'...
        };
    
    runWorkflow('makehdltb', cbinfo, pv_args)
end

function GenerateSVDPICB(cbinfo)
% makehdltb with System Verilog DPI-C callback
    tool = getHDLSimTool(cbinfo.model.Name);
    
    pv_args = {...
        'GenerateHDLTestBench', 'off', ...
        'GenerateCoSimModel', 'none', ...
        'GenerateSVDPITestBench', tool ...
        };
    
    runWorkflow('makehdltb', cbinfo, pv_args);
end

function OpenHdlCodeViewCB(userdata, cbinfo)
% Launch code view panel for HDL coder

    % check if the HDL coder license is checked out
    slhdlcoder.checkLicense;
    
    studio = cbinfo.studio;    
    contextManager = studio.App.getAppContextManager;
    customContext = contextManager.getCustomContext(userdata);
    if isempty(customContext.hdlCodeView)
        customContext.hdlCodeView = simulinkcoder.internal.CodeView_HDL(studio);
    end
    
    customContext.hdlCodeView.open('', true);
    
end

function OpenHDLRptCB(cbinfo)
% open either the HDL Check Report or HDL Codegen Report
    % fetch codegen report path
    rptPath = hdlcoder.report.ReportInfo.getSavedRptPath(cbinfo.model.Name, true);
    if isempty(rptPath)
        % no codegen report exists, open check report instead
        rptPath = hdlcoder.report.ReportInfo.getSavedRptPath(cbinfo.model.Name, false);
    end
    % open in new window in case user has web window already open
    import matlab.internal.capability.Capability;
    if Capability.isSupported(Capability.LocalClient)
        % Local Client(Desktop)
        web(rptPath);
    else
        % online 
        hdlcoder.report.openDdg(rptPath);
    end
end

function OpenCodeMappingsCB(cbinfo)
    % open code mappings spreadsheet
    openIPCoreUI(cbinfo);
end

function OpenIPCoreSettingsCB(cbinfo)
    % open IP core settings
    openIPCoreUI(cbinfo);    
end

function OpenDeploymentSettingsCB(cbinfo)
    % open IP core project settings
    openDeploymentSettingsUI(cbinfo);
end

function CreateHDLProjectCB(cbinfo)
    model = cbinfo.model.name;  
    % Create diagnostic viewer stage for the IP core run and show the stage
    % to indicate progress.
    % Get taskName for DV stage
    taskName = message('hdlcoder:toolstrip:CreateIPProjectHdlCoderActionText').getString;
    validateWorkflowAdvisorAndConfigsetStatus(model, taskName);

    codeGenStage = sldiagviewer.createStage(taskName, ModelName=model); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(model);
    % setUIsCodegenInProgress to true and cleaning up when done  
    setUIsCodegenInProgress(cbinfo, true);
    UIEnable = onCleanup(@() setUIsCodegenInProgress(cbinfo, false));
    
    runCreateIPCoreProject(model);
end

function BuildBitstreamCB(cbinfo)
    model = cbinfo.model.name;
    % Get taskName for DV stage
    taskName = message('hdlcoder:toolstrip:BuildBitstreamHdlCoderActionText').getString;
    taskName = replace(taskName, newline, ' ');
    validateWorkflowAdvisorAndConfigsetStatus(model, taskName);

    BuildBitstreamStage = sldiagviewer.createStage(taskName,...
                  'ModelName', model); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(model);
    % Add "starting" message to diagnostic viewer    
    Simulink.output.info(['### ', message('hdlcommon:workflow:BuildBitstreamStart', cbinfo.model.Name).getString]);
    % setUIsCodegenInProgress to true and cleaning up when done    
    setUIsCodegenInProgress(cbinfo, true);
    UIEnable = onCleanup(@() setUIsCodegenInProgress(cbinfo, false));

    runBuildBitstream(model);
end

function HDLProgramTargetDeviceCB(cbinfo)
    % Program target device in reference design workflow
    % Get task name for DV Category name
    taskName = message('hdlcoder:toolstrip:ProgramTargetDeviceHdlCoderActionText').getString;
    taskName = replace(taskName, newline, ' ');
    model = cbinfo.model.name;
        
    programDeviceStage = sldiagviewer.createStage(taskName,...
        'ModelName', model); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(model);

    validateWorkflowAdvisorAndConfigsetStatus(model, taskName);

    try
        % Get downstream integration driver handle and load top-level
        % settings        
        [hDI, cleanup] = getDownstreamIntegrationDriver(model); %#ok<ASGLU>
        % Add "starting" message to diagnostic viewer
        Simulink.output.info(['### ', message('hdlcommon:workflow:ProgramTargetStart').getString]);
        [status, logTxt, validateCell] = hDI.runEmbeddedDownloadBitstream;
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(model, msg, severity, false,  Category=taskName);
        return;
    end
    validateCell = downstream.tool.filterEmptyCell(validateCell);
    % task status message
    if status
        % pass message at the end
        Simulink.output.info({'hdlcoder:hdldisp:ProgramTargetDeviceSuccess'});
        if (~isempty(validateCell))
            % Display warnings when program target device is succesful
            downstream.tool.displayValidateCellToDiagnosticViewer(model, validateCell, false, Category=taskName);
        end
    else
        % fail message . Errors are routed to the log which is subsequently
        % displayed.
        Simulink.output.error({'hdlcommon:workflow:ProgramTargetDeviceFailure'});
    end

    if (~isempty(logTxt))
        % Display log contents
        Simulink.output.info({'hdlcommon:workflow:ProgramTargetLog'});
        Simulink.output.info(logTxt);
    end

end

function HDLExportToScriptCB(cbinfo) 
    % Export all the config settings to a script
    % Get taskName for DV stage
    taskName = message('hdlcoder:toolstrip:ExportWorkflowHdlCoderActionText').getString;

   
    % Export HDL Workflow script callback
    modelName = cbinfo.model.name;
    dutName = hdlget_param(modelName,'HDLSubsystem');

    ExportWorkflowScript = sldiagviewer.createStage(taskName,...
                  'ModelName', modelName); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(modelName);

    validateWorkflowAdvisorAndConfigsetStatus(modelName, taskName);

    [FileName,PathName] = uiputfile('*.m','Export Workflow Configuration','hdlworkflow.m');
    
    %Return if canceled
    if ( FileName == 0 )
        return;
    end
    
    file = fullfile(PathName,FileName);
    
    %  Display loading bar
    loadingBar = waitbar(0.4, DAStudio.message('hdlcoder:workflow:ExportToScript'));
    c = onCleanup(@() delete(loadingBar));
  
    try
        % Get downstream integration driver handle and load top-level
        % settings
        [hDI, cleanup] = getDownstreamIntegrationDriver(modelName); %#ok<ASGLU>

        % Check that the advisor is ok to export (workflow and tool)
        tool = hDI.get('Tool');
        workflow = hDI.get('Workflow');

        % Create Workflow Config Object
        hWC = hdlcoder.WorkflowConfig('SynthesisTool',tool,'TargetWorkflow',workflow);
        hWC.importWorkflowTasksFromDriver(hDI, modelName, tool);

        % Write the file
        hWC.export('Filename',file,'DUT',dutName,'Comments',true,'Headers',true,'Overwrite',true,'Warn',false, ...
            'DownstreamDriver', hDI);
        % Update waitbar
        waitbar(0.8,loadingBar,DAStudio.message('hdlcoder:workflow:ExportSuccess'));
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(modelName, msg, severity, false,  Category=taskName);
        return;
    end
    
    % Update waitbar
    waitbar(1,loadingBar);
    pause(1); % Pause before closing
end

function HDLExportProgrammingToScriptCB(cbinfo)
    % Export all the config settings to a script
    % Get taskName for DV stage
    taskName = message('hdlcoder:toolstrip:ExportProgrammingHdlCoderActionText').getString;        
    
    % Generate HDL Export Programming Script callback
    modelName = cbinfo.model.name;
    dutName = hdlget_param(modelName,'HDLSubsystem');

    ExportProgrammingScript = sldiagviewer.createStage(taskName,...
                  'ModelName', modelName); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(modelName);
    
    validateWorkflowAdvisorAndConfigsetStatus(modelName, taskName);

    [FileName,PathName] = uiputfile('*.m','Export Programming Script','hdlworkflow_ProgramTargetDevice.m');
    
    %Return if canceled
    if ( FileName == 0 )
        return;
    end
    
    file = fullfile(PathName,FileName);
    
    %  Display loading bar
    loadingBar = waitbar(0.4, DAStudio.message('hdlcoder:workflow:ExportToScript'));
    c = onCleanup(@() delete(loadingBar));

    % Write the file
    try
        % Get downstream integration driver handle and load top-level
        % settings
        [hDI, cleanup] = getDownstreamIntegrationDriver(modelName); %#ok<ASGLU>

        % Check that the advisor is ok to export (workflow and tool)
        [tool, workflow, hdl_prj, toolVer, mismatch , method] = hDI.getProgrammingSettingsAsStrings;

        % Create Workflow Config Object
        hWC = hdlcoder.WorkflowConfig('SynthesisTool',tool,'TargetWorkflow',workflow);
        % Update waitbar
        waitbar(0.8,loadingBar,DAStudio.message('hdlcoder:workflow:ExportSuccess'));        
        hWC.exportProgrammingScript(hdl_prj, toolVer, mismatch , method, dutName, file);   
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(modelName, msg, severity, false,  Category=taskName);
        return;
    end
    
    % Update waitbar
    waitbar(1,loadingBar);
    pause(1); % Pause before closing
end

function HDLExportSoftwareModelCB(cbinfo)
    % Export Simulink Software Interface Model in reference design workflow
    % Get task name for DV Category name
    taskName = message('hdlcoder:toolstrip:SoftwareInterfaceModelHdlCoderActionText').getString;
    taskName = replace(taskName, newline, ' ');
    modelName = cbinfo.model.name;
    
    ExportHostScriptStage = sldiagviewer.createStage(taskName,...
                  'ModelName', modelName); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(modelName);

    validateWorkflowAdvisorAndConfigsetStatus(modelName, taskName);
    
    try
        [hDI, cleanup, validateCell] = getDownstreamIntegrationDriverWithTableLoaded(cbinfo, taskName); %#ok<ASGLU>
        hDI.validateSoftwareInterfaceModelGeneration(modelName, taskName);
        Simulink.output.info(['### ', message('hdlcommon:workflow:HDLWASWInterfaceModel').getString]); 
        [~, result, validateCell2] = hDI.hIP.runSWInterfaceGenSpecifiedTask('GenerateSoftwareInterfaceModel');
        validateCell = [validateCell, validateCell2];
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(modelName, msg, severity, false,  Category=taskName);
        return;
    end

    % Display any validations
    validateCell = downstream.tool.filterEmptyCell(validateCell);
    Simulink.output.info(result);
    if (~isempty(validateCell))
        downstream.tool.displayValidateCellToDiagnosticViewer(modelName, validateCell, false, Category=taskName);        
    end
end

function HDLExportHostScriptCB(cbinfo)
    % Export host interface scripts in reference design workflow
    % Get task name for DV Category name
    taskName = message('hdlcoder:toolstrip:HostInterfaceScriptHdlCoderActionText').getString;
    taskName = replace(taskName, newline, ' ');
    modelName = cbinfo.model.name;
    ExportHostScriptStage = sldiagviewer.createStage(taskName,...
                  'ModelName', modelName); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(modelName); 

    validateWorkflowAdvisorAndConfigsetStatus(modelName, taskName);

    try
        [hDI, cleanup, validateCell] = getDownstreamIntegrationDriverWithTableLoaded(cbinfo, taskName); %#ok<ASGLU>        
        Simulink.output.info(['### ', message('hdlcommon:workflow:HDLWASWInterfaceScript').getString]);
        [~, result, validateCell2] = hDI.hIP.runSWInterfaceGenSpecifiedTask('GenerateHostInterfaceScript');
        validateCell = [validateCell, validateCell2];
        [validateCell] = hDI.validateInterfaceScript(modelName, validateCell);
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(modelName, msg, severity, false,  Category=taskName);
        return;
    end

    % Display any validations
    validateCell = downstream.tool.filterEmptyCell(validateCell);
    Simulink.output.info(result);
    if (~isempty(validateCell))
        downstream.tool.displayValidateCellToDiagnosticViewer(modelName, validateCell, false, Category=taskName);        
    end    
end

function HDLExportHostModelCB(cbinfo)
    % Export host interface models in reference design workflow
    % Get task name for DV Category name
    taskName = message('hdlcoder:toolstrip:HostInterfaceModelHdlCoderActionText').getString;   
    modelName = cbinfo.model.name;

    ExportHostScriptStage = sldiagviewer.createStage(taskName,...
                  'ModelName', modelName); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(modelName); 

    validateWorkflowAdvisorAndConfigsetStatus(modelName, taskName);

    try
        [hDI, cleanup, validateCell] = getDownstreamIntegrationDriverWithTableLoaded(cbinfo, taskName); %#ok<ASGLU>
        [~, result, validateCell2] = hDI.hIP.runSWInterfaceGenSpecifiedTask('GenerateHostInterfaceModel');
        validateCell = [validateCell, validateCell2];
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(modelName, msg, severity, false,  Category=taskName);
        return;
    end

    % Display any validations
    validateCell = downstream.tool.filterEmptyCell(validateCell);
    Simulink.output.info(result);
    if (~isempty(validateCell))
        downstream.tool.displayValidateCellToDiagnosticViewer(modelName, validateCell, false, Category=taskName);
    end
end

function SelectHostTargetInterfaceCB(userdata, cbinfo)
    % Modify HostTargetInterface in downstream integration driver with the
    % information selected on the dropdown in the toolstrip   
    state = cbinfo.EventData; % whether the button was being depressed or raised.
    if( state )
        modelName = cbinfo.model.name;
        [hDI, cleanup] = getDownstreamIntegrationDriver(modelName); %#ok<ASGLU>
        hDI.hIP.setHostTargetInterface(userdata);
        hdlcoder.DeploymentSettings.saveDIDeploymentSettingsToModel(hDI);
    end
end

%% Helper functions
function [path, name, selectedSystem, isPinned] = getSelectedSystem(cbinfo)
    % get chosen system in the system selector
    [isUsingToolstrip, systemSelectorAction] = isCallFromToolstrip(cbinfo);
    if isUsingToolstrip
        % call back executed using toolstrip
        pinnedSystem = cbinfo.studio.App.getPinnedSystem(systemSelectorAction.name);
        isPinned = ~isempty(pinnedSystem);
        if isPinned
            % give priority to pinned system if it exists
            selectedSystem = pinnedSystem;
        else
            selection = cbinfo.getSelection;
            % check if a single system is selected
            if size(selection) == 1
                % pass the selection
                if ~isprop(selection, 'Name') || isempty(selection.Name)
                    % selected object is not a system or block, grab the
                    % system in the current view instead
                    selectedSystem = cbinfo.uiObject;
                else
                    selectedSystem = selection;
                end
            else
                % pass the system in the current view
                selectedSystem = cbinfo.uiObject;
            end
        end
        name = selectedSystem.name;
        path = selectedSystem.getFullName;
    else
        % callback is from legacy global menu
        % get selected system from config params
        hdlcc = hdlcodermenus('loc_getHDLCC', cbinfo);
        if ~isempty(hdlcc)
            path = hdlcc.getCLI.HDLSubsystem;
            name = get_param(path, 'Name');
        else
            path = [];
            name = [];
        end
        selectedSystem = [];
        isPinned = false;
    end
end

function val = hasHDLConfig(cbinfo)
    val = ~isempty(hdlcodermenus('loc_getHDLCC', cbinfo));
end

function [val, systemSelectorAction] = isCallFromToolstrip(cbinfo)
% return false if callback is not from the toolstrip
% callback is from a legacy schema
    toolstrip = cbinfo.studio.getToolStrip();
    systemSelectorAction = toolstrip.getAction('selectSystemHdlCoderComboBoxAction');
    if ~isempty(systemSelectorAction)
        val = true;
    else
        val = false;
    end
end

function [hDI, cleanup] = getDownstreamIntegrationDriver(modelName)

hdlcc = gethdlcc(modelName);
hDI = hdlcc.getDownstreamIntegrationDriver;

% Set cliDisplay = true to reduce the number of compilation times and
% display log info during codegen in diagnostic viewer
cleanup = onCleanup(@() hDI.setCliDisplay(false));
hDI.cliDisplay = true;

end

function [hDI, cleanup, validateCell] = getDownstreamIntegrationDriverWithTableLoaded(cbinfo, taskName)
    % Get model name
    modelName = cbinfo.model.name;
    % Get downstream integration driver handle and load top-level settings
    [hDI, cleanup] = getDownstreamIntegrationDriver(modelName);

    if hDI.hTurnkey.hTable.isInterfaceTableEmpty
        % Target interface table needs to be loaded in order to generate
        % host/software interface script/model. If table isn't loaded yet,
        % load it here.
        Simulink.output.info(['### ', message('hdlcommon:workflow:ConstructTargetInterfaceTableBegin').getString]);
        modelCleanUp = onCleanup(@() safeCloseConnection(hDI.hCodeGen.hCHandle)); % Release model from compiled state in CLI mode
        msg = hDI.loadDUTLevelSettings(true);
        downstream.tool.displayExceptionCellToDiagnosticViewer(modelName, msg, 'Warning', false, Category="Load IP Core Settings");
        Simulink.output.info(['### ', message('hdlcommon:workflow:ConstructTargetInterfaceTableComplete').getString]);
    else
        % Target interface was previously loaded. We don't explicitly
        % reload the table here, so we display message saying that the
        % host/software interface model/ script is being generated based on
        % the last stored target interface table. If the model had any
        % changes (e.g. updated ports / port data types), these wouldn't be
        % taken into account. Note that this is different from the code
        % generation and build tasks, where we always build from the
        % latest version of the model.

        % Provide a link to open the Interface Table
        % Get Studio tag (string) to retrieve the studio in the hyperlink
        studioTag = cbinfo.studio.getStudioTag();
        cmd = sprintf('<a href="matlab:studio= DAS.Studio.getStudio(''%s'');',studioTag);
        cmd = sprintf('%sdutPath = hdlget_param(''%s'', ''HDLSubsystem'');',cmd, modelName);
        cmd = sprintf('%sdutHandle = get_param(dutPath, ''Handle'');',cmd);
        cmd = sprintf('%shdlturnkey.ui.manager.GlobalManager.openUI(dutHandle, studio, hdlturnkey.ui.MappingSpreadSheetTab.TabName);',cmd);
        cmd = sprintf('%s">%s</a>',cmd,"Interface Mapping");
        Simulink.output.warning({'hdlcommon:workflow:SimulinkCanvasExportWorkflow', taskName, cmd});
    end

    % Validate interface table
    validateCell = hDI.hTurnkey.hTable.validateTable;
    validationFailed = downstream.tool.hasErrorInValidateCell(validateCell);  
    if validationFailed
        % if validation failed return early and emit messages to DV
        downstream.tool.displayValidateCellToDiagnosticViewer(modelName, validateCell, false, Category=taskName);
        error(message('hdlcommon:workflow:MappingValidationFailed', modelName));
    end
end

function runWorkflow(fcnStr, cbinfo, args)
% central call for functions which print to the diagnostic viewer
    if nargin < 3
        args = {};
    end
    systemPath = getSelectedSystem(cbinfo);
    fcnArgs = cat(2, systemPath, args);
    try
        feval(fcnStr, fcnArgs{:});
    catch e
        hdl_coder_auto_build_stage = Simulink.output.Stage('HDLCoder', 'ModelName', cbinfo.model.Name, 'UIMode', true);             %#ok<NASGU>
        Simulink.output.error( e,'Component','HDLCoder','Category','HDL');
    end
end

function successIPCore = runIPCoreGeneration(model)
    successIPCore = false;

    taskName = message('hdlcoder:toolstrip:GenerateIPHdlCoderActionText').getString;
    taskName = replace(taskName, newline, ' ');

    % Create diagnostic viewer stage for the IP core run and show the stage
    % to indicate progress.
    codeGenStage = sldiagviewer.createStage(taskName, ModelName=model); %#ok<NASGU>
    downstream.tool.openDiagnosticViewer(model);

    % Add starting message indicating IP Core generation started to diagnostic viewer    
    Simulink.output.info(['### ', message('hdlcommon:workflow:IPCoreGenerationStart', model).getString]);

    % Early tool validation before initiating workflow, at this point hDI
    % is not available to query "hDI.isToolIndependentPlatform" so to avoid
    % and error during early tool loading/validation for "Generic Platform"
    % we only perform the validation when the tool is not empty
    toolName = hdlget_param(model, 'SynthesisTool');
    if(~isempty(toolName))
        if ~downstream.AvailableToolList.isToolOnPath(toolName)
            % Attempt to refresh tool path if not found
            downstream.AvailableToolList.refreshToolPath(toolName);
        end
        
        if ~downstream.AvailableToolList.isToolOnPath(toolName)
            % Error out with instructions to setup the tool path
            Simulink.output.error(message('hdlcommon:workflow:SynthesisToolNotAvailable',...
                toolName, 'help hdlsetuptoolpath').getString);
            return;
        end
    end

    % IP Core Validations and HDL Checks
    % Interface Table stage
    validationStage = sldiagviewer.createStage(message('HDLShared:hdldialog:IPCoreValidation').getString,...
                  'ModelName', model);

    % Check current folder
    rtw_checkdir;

    % Get current hdlcodegen mode so we can restore it on cleanup
    oldCodeGenMode      = hdlcodegenmode;
    codeGenModeCleanup  = onCleanup(@() hdlcodegenmode(oldCodeGenMode));
    % Set the coder mode to 'slcoder'. Since we will only do one
    % compilation for the model when possible, we need to set the mode to
    % slcoder so when makehdl restores it to the mode it was on before
    % makehdl was called it goes back to slcoder and not to filtercoder
    % which is the default before any workflow has been done. 
    % We also need slcoder mode so hdldisp generates an output.
    hdlcodegenmode('slcoder');

    try
        % Get downstream integration driver handle and load the latest
        % settings from the model
        [hDI, cleanup] = getDownstreamIntegrationDriver(model); %#ok<ASGLU>

        if ~hDI.hTurnkey.hTable.isInterfaceTableEmpty
            % Save current mappings in the interface table to the model.
            % This way when we reload from the model we use the latest
            % settings in the table
            hDI.hTurnkey.hTable.savePortInterfaceToModel;
        end

        % Load latest settings from the model
        msg = {};
        msg1 = hDI.loadTopLevelSettings();
        msg = [msg msg1];
        msg1 = hDI.loadDUTLevelSettings();
        msg = [msg msg1];

        % Report any issues when loading settings from the model
        downstream.tool.displayExceptionCellToDiagnosticViewer(model, msg, 'Error', false, Category="Load IP Core Settings");
        if ~isempty(msg)
            error(message('hdlcommon:workflow:ApplySettingErrorFromModel'));
        end
    catch ME
        % Auto clean up to close the compiled model when skipping multiple
        % compilations.
        % As the hDI might be empty in some cases, we
        % add protection here to close the compiled model
        msg = {ME};
        severity = 'Error';
        hdlcoderObj = downstream.CodeGenInfo.getCodeGenHandle(model);
        autoCleanUp = onCleanup(@() safeCloseConnection(hdlcoderObj));
        downstream.tool.displayExceptionCellToDiagnosticViewer(model, msg, severity, false, Category= taskName);
        cr = simulinkcoder.internal.Report.getInstance;
        crCleanup = onCleanup(@() cr.unlock(model)); % unlock code view
        return;
    end

    % Auto clean up to close the compiled model
    % Once we get to this stage, the hDI object is non-empty and here add
    % another protection to closed the compiled model.
    hdlcoderObj = hDI.hCodeGen.hCHandle;
    autoCleanUp = onCleanup(@() safeCloseConnection(hdlcoderObj));

    % Validations
    validateCell = hDI.validateIPCoreSettings(true, true);

    downstream.tool.displayValidateCellToDiagnosticViewer(model, validateCell, false, Category=taskName);
    validationStage.delete;

    validationFailed = downstream.tool.hasErrorInValidateCell(validateCell);
    if validationFailed
        % Return early if validation failed
        cr = simulinkcoder.internal.Report.getInstance;
        crCleanup = onCleanup(@() cr.unlock(model)); % unlock code view
        return;
    end


    %% Run code generation
    try
        % Create IP Core generation diagnostic viewer stage
        IPCoreGenStage = sldiagviewer.createStage(message('HDLShared:hdldialog:HDLWAGenerateIPCore').getString,...
            'ModelName',model);
        msg = message('hdlcommon:workflow:IPCoreGenerationStart', model);
        % Display start of IP core generation
        hdldisp(msg);
        % hdldisp messages will be directed to the diagnostic viewer since
        % we are using the Simulink.output.info API and there is an active
        % stage.
        % TODO: Redirect messages emitted from c++ to diagnostic viewer.
        % Currently these messages will be displayed in the command window. 
        validateCell = hDI.runIPCoreCodeGen;
        % Display validations
        downstream.tool.displayValidateCellToDiagnosticViewer(model, validateCell, false, Category=taskName);
        % Display Workflow Complete message
        msg = message('hdlcommon:workflow:HWCLIWorkflowComplete');        
        hdldisp(msg);  
        IPCoreGenStage.delete;
        successIPCore = true;
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(model, msg, severity, false,  Category=taskName);
    end
end

function successIPCoreProject = runCreateIPCoreProject(model)
    successIPCoreProject = false;

    taskName = message('hdlcoder:toolstrip:CreateIPProjectHdlCoderActionText').getString;

    % IP core generation
    successIPCore = runIPCoreGeneration(model);
    if ~successIPCore
        return;
    end
    % Get downstream integration driver handle
    [hDI, cleanup] = getDownstreamIntegrationDriver(model); %#ok<ASGLU>
    try
        projectCreationStage = sldiagviewer.createStage(taskName,...
                  'ModelName', model); %#ok<NASGU>
        Simulink.output.info(['### ', message('hdlcommon:workflow:IPCoreProjectCreate', model).getString]);
        [successIPCoreProject, logTxt] = hDI.runCreateEmbeddedProject;
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(model, msg, severity, false);
        return;
    end
    Simulink.output.info(logTxt);
    if successIPCoreProject
        Simulink.output.info(['### ' message('hdlcoder:hdldisp:IPCoreCreateEmbeddedProjectSuccess').getString]);
    else
        Simulink.output.error(['### ' message('hdlcoder:hdldisp:IPCoreCreateEmbeddedProjectFailure').getString]);
    end    
end

function runBuildBitstream(model)
    taskName = message('hdlcoder:toolstrip:BuildBitstreamHdlCoderActionText').getString;
    taskName = replace(taskName, newline, ' ');

    % First run project creation
    successIPCoreProject = runCreateIPCoreProject(model);
    if ~successIPCoreProject        
        return;
    end

    % Get downstream integration driver handle
    [hDI, cleanup] = getDownstreamIntegrationDriver(model); %#ok<ASGLU>
    
    try
        projectCreationStage = sldiagviewer.createStage(taskName, ...
                  'ModelName', model); %#ok<NASGU>
        [Result, logTxt, validateCell] = hDI.runEmbeddedSystemBuild;
        downstream.tool.displayValidateCellToDiagnosticViewer(model, validateCell, false, Category=taskName);
    catch ME
        msg = {ME};
        severity = 'Error';
        downstream.tool.displayExceptionCellToDiagnosticViewer(model, msg, severity, false, Category=taskName);
        return;
    end    
    
    Simulink.output.info(logTxt);
    if Result
        Simulink.output.info(['### ' message('hdlcoder:hdldisp:IPCoreBuildEmbeddedSystemSuccess').getString]);
    else
        Simulink.output.error(['### ' message('hdlcoder:hdldisp:IPCoreBuildEmbeddedSystemFailure').getString]);
    end

    % Run device tree generation
    if hDI.hIP.GenerateDeviceTree
        [Result, logTxt, validateCell] = hDI.hIP.generateDeviceTrees(hDI.hTurnkey);
        Simulink.output.info(logTxt);
        downstream.tool.displayValidateCellToDiagnosticViewer(model, validateCell, false, Category=taskName);        
        if(~Result)
            Simulink.output.error(['### ' message('hdlcommon:workflow:DeviceTreeGenMsgFail').getString]);
        end
    end
end

function tool = getHDLSimTool(mdlName)
    tool = hdlget_param(mdlName, 'SimulationTool');
    if strcmpi(tool, 'mentor graphics modelsim')
        tool = 'ModelSim';
    elseif strcmpi(tool, 'cadence incisive')
        tool = 'Incisive';
    elseif strcmpi(tool, 'xilinx vivado simulator')
        tool = 'Vivado Simulator';
    elseif strcmpi(tool,'synopsys vcs')
        tool = 'VCS';
    end
end

function checkReferenceHierarchy(cbinfo, action)
    [selectedSystemPath, ~, obj] = getSelectedSystem(cbinfo);
    if strcmp(systemSelectorStateFcn(obj), 'nonsupported')
        % invalid system for code generation, no need to check hierarchy
        return
    end
    selectedModel = bdroot(selectedSystemPath);
    topModel = cbinfo.model.Name;
    if ~strcmp(selectedModel, topModel)
        % top model and system for code generation must be the same for HDL
        % toolstrip to avoid confusion on config settings
        action.enabled = false;
        if strcmp(action.name, 'selectSystemHdlCoderComboBoxAction')
            % override any other previously set messaging
            action.validationState = 'error';
            action.errorText = message('hdlcoder:toolstrip:SystemSelectorReferenceHierarchy').string;
        end
    end
end

function val = isSelectionValidHDLBlock(cbinfo)
% Determines if the selected object in Simulink is a possible block for HDL code generation
% Used to enable HDL Block Properties and Navigate to Code buttons.
    blocks = cbinfo.getSelection;

    val = ...
        ~contains('simulinkCanvas',cbinfo.Context.TypeChain) && ... % something is selected
        ~contains('signal',cbinfo.Context.TypeChain) && ... % not a Simulink signal
        ~contains('state',cbinfo.Context.TypeChain) && ... % not inside Stateflow chart
        ~contains('area',cbinfo.Context.TypeChain) && ... % not a Simulink area
        ~contains('annotation',cbinfo.Context.TypeChain) && ... % not a Simulink annotation
        numel(blocks) == 1 && ... % only one block can be selected
        ~isBusElementPort(blocks); % not a bus element port
end

function updatePinnedSystem(cbinfo)
% if a HDL System exists in the config params and the system selector is
% not pinned, then override the system selector with the HDL System and set
% it to be pinned
    hdlSystem = hdlget_param(cbinfo.model.Name, 'HDLSubsystem');
    [~, ~, ~, isPinned] = getSelectedSystem(cbinfo);
    [~, systemSelectorAction] = isCallFromToolstrip(cbinfo);
    if ~isPinned && ~isempty(systemSelectorAction)
        % system selector should only be updated if visible
        insertPinnedSystem(hdlSystem, cbinfo, systemSelectorAction);
    end
end

function insertPinnedSystem(systemPath, cbinfo, action)
    try
        name = get_param(systemPath, 'Name');
        action.validateAndSetEntries({name});
        action.selectedItem = name;
        action.description = systemPath;

        obj = get_param(systemPath, 'object');
        cbinfo.studio.App.insertPinnedSystem(action.name, obj, Simulink.ID.getSID(obj));
    catch me
        % if the HDL Subsystem is not a valid Simulink object, don't do
        % anything
        assert(strcmp(me.identifier, 'Simulink:Commands:InvSimulinkObjectName'), ...
            'unexpected error found while trying to pin HDL Subsystem');
    end
end

function isit = isIPCoreGenerationWorkflow(cbinfo)
    isit = strcmp(hdlget_param(cbinfo.model.name, 'Workflow'), 'IP Core Generation');
end

function openIPCoreUI(cbinfo)
    dutHandle = getDUTHandle(cbinfo);
    studio = cbinfo.studio;
    hdlturnkey.ui.manager.GlobalManager.openUI(dutHandle, studio);
end

function closeIPCoreUI(cbinfo)
    dutHandle = getDUTHandle(cbinfo);
    studio = cbinfo.studio;
    hdlturnkey.ui.manager.GlobalManager.closeUI(dutHandle, studio);
end

function openDeploymentSettingsUI(cbinfo) 
    studio = cbinfo.studio;
    modelHandle = studio.App.blockDiagramHandle;    
    hdlturnkey.ui.manager.GlobalManager.openHDLDeploymentSettingsUI(modelHandle, studio);
end

function closeDeploymentSettingsUI(cbinfo) 
    studio = cbinfo.studio;
    modelHandle = studio.App.blockDiagramHandle;    
    hdlturnkey.ui.manager.GlobalManager.closeHDLDeploymentSettingsUI(modelHandle, studio);
end

function closeAllIPCoreUIs(cbinfo) 
    studio = cbinfo.studio;
    modelHandle = studio.App.blockDiagramHandle;
    hdlturnkey.ui.manager.GlobalManager.closeAllIPCoreUIs(modelHandle);
end

function [hostTargetInterface] = getHostTargetInterface(cbinfo)
    modelName = cbinfo.model.name;
    [hDI, cleanup] = getDownstreamIntegrationDriver(modelName); %#ok<ASGLU>
    hostTargetInterface = hDI.hIP.getHostTargetInterfaceForToolstrip;
end

function validateWorkflowAdvisorAndConfigsetStatus(modelName, taskName)
    % Error out if HDLWA is open
    if hdlwa.isWorkflowAdvisorOpenForModel(modelName)
        error(message('hdlcommon:workflow:WorkflowAdvisorOpen', taskName));
    end

    % Error out if configset has unapplied changes to target pane
    downstream.tool.validateConfigSetUnappliedChanges(modelName, taskName);
end

function setUIsCodegenInProgress(cbinfo, value) 
    studio = cbinfo.studio;
    modelHandle = studio.App.blockDiagramHandle;
    hdlturnkey.ui.manager.GlobalManager.setUIsCodegenInProgress(modelHandle, value);
end

function dutHandle = getDUTHandle(cbinfo)
    dutPath = hdlget_param(cbinfo.model.Name, 'HDLSubsystem');
    try
        dutHandle = get_param(dutPath, 'Handle');
    catch
       error(message('hdlcommon:workflow:InvalidDUTSubsystem',dutPath));
    end
end

function safeCloseConnection(hdlcoderObj)
    % safe auto clean up function
    try %#ok<TRYNC>
        % Close the model connection
        if ~isempty(hdlcoderObj) && ~isempty(hdlcoderObj.ModelConnection)
            % Terminate model compiled state and Restore cached settings
            hdlcoderObj.closeConnection();
        end
    
        % Clean up if the codegen is unsuccessful
        codegenStatus = hdlcoderObj.CodeGenSuccessful;
        if ~codegenStatus && ~isempty(hdlcoderObj.hs)
            hdlcoderObj.cleanup(hdlcoderObj.hs, codegenStatus);
        end
        % There are different cases this cleanup is not needed and
        % if there is a failure, we just don't do anything further.
        % (1). hdlcoderObj is empty
        % (2). hdlcoderObj.modelconnection is empty
        % (3). hDI did not exist
        % (4). hDI exists, and the PIR has been created, but we
        %      haven't go to the state to create the codegenParams.
        % (5). PIR created, part of the codegenParams has been created,
        %      but we are missing the hs parameter
        % (6). hs parameter has been cleared as the codegen is
        %      finished.
    end
end

function OpenHDLPropInspectorCB(cbinfo)
    studio = cbinfo.studio;
    hdlpi = studio.getComponent('GLUE2:PropertyInspector','HDL Property Inspector');
    if isempty(hdlpi)
        modelHandle = studio.App.blockDiagramHandle;
        if isempty(cbinfo.getSelection)
            % canvas is selected at some level
            blockHandle = studio.App.getCurrentSelection.handle;
        else
            % something is selected
            blockHandle = cbinfo.getSelection.Handle;
        end
        HDLPropertyInspector.create(modelHandle,blockHandle,false);
    else
        if ~hdlpi.isVisible
            studio.showComponent(hdlpi);
        else
            if hdlpi.isMinimized
                hdlpi.ShowMinimized = false;
            end
            studio.hideComponent(hdlpi);
        end
    end
end

function OpenHDLPropInspectorRF(cbinfo,action)
    hdlpi = cbinfo.studio.getComponent('GLUE2:PropertyInspector','HDL Property Inspector');
    if isempty(hdlpi)
        action.selected = false;
    else
        action.selected = hdlpi.isVisible;
    end
end