classdef helperBLEVisualizeCoexistence < handle
%helperBLEVisualizeCoexistence Create an object for BLE and WLAN
%coexistence visualization
%   OBJ = helperBLEVisualizeCoexistence creates an object for BLE and WLAN
%   coexistence model visualization with default values.
%
%   OBJ = helperBLEVisualizeCoexistence(Name, Value) creates a BLE and WLAN
%   coexistence model visualization object with the specified property Name
%   set to the specified Value. You can specify additional name-value pair
%   arguments in any order as (Name1, Value1, ..., NameN, ValueN).
%
%   helperBLEVisualizeCoexistence properties:
%
%   Action                       - The action to be performed in
%                                  visualization
%   WLANChannelIdx               - WLAN channel index
%   CollisionProbability         - WLAN channel collision probability
%   SlaveNumber                  - BLE Slave number
%   SlaveCount                   - Number of BLE Slaves
%   ChannelMap                   - BLE channel map representing the
%                                  good or bad channel
%   BLEChannelNumber             - BLE channels number
%   OverallSuccessRate           - Over all success rate per channel
%   WLANChannelList              - List of WLAN channels
%   ClassificationInterval       - Periodicity of channel classification
%   PERThreshold                 - Packet error rate (PER) threshold
%   ChannelBusyCountThreshold    - Channel busy count threshold
%   PreferredMinimumGoodChannels - Preferred number of good channels
%   ConnectionInterval           - Connection interval
%   Stoptime                     - Simulation stop-time
%   CurrentTime                  - Current simulation time
%   PHYMode                      - Physical layer operating mode
%   EnableVisualization          - Enable/disable the visualization
%   EnableHoppingVisualization   - Enable/disable the visualization of
%                                  channel hopping sequence

%   Copyright 2018-2019 The MathWorks, Inc.
    
properties
    %Action The action to be performed in visualization
    %   Specify the action as one of 'Initialize' | 'Add WLAN channel' |
    %   'Remove WLAN channel' | 'Active ble channel' | 'Update channel map'
    %   | 'Failed to update channel map' | 'Corrupted ble channel' |
    %   'Simulation Progress'. It specifies the action to be performed in
    %   visualizing the coexistence model. The default value is
    %   'Initialize'.
    Action = 'Initialize'

    %WLANChannelIdx WLAN channel index
    %   Specify the WLAN channel index as an integer value in the range [1,
    %   14]. It indicates the index of the WLAN channel that is added to or
    %   deleted from visualization. The default value is 1.
    WLANChannelIdx = 1

    %CollisionProbability WLAN channel collision probability
    %   Specify the collision probability as real value in the range [0,
    %   1]. It indicates the collision probability of the WLAN channel. The
    %   default value is 0.
    CollisionProbability = 0

    %SlaveNumber BLE Slave number
    %   Specify the Slave number as an integer value in the range [1, 5]
    %   representing the current BLE Slave number. The default value is 1.
    SlaveNumber = 1

    %SlaveCount Number of BLE Slaves
    %   Specify the Slave count as an integer value in the range [1, 5]
    %   representing the number of BLE Slaves. The default value is 1.
    SlaveCount = 1
    
    %ChannelMap BLE channel map representing the good or bad channel
    %   Specify the channel map as an integer array of size 37 and each
    %   value should be either 0 or 1. It indicates the status of the each
    %   data channel of the BLE. The value 0 indicates 'bad channel' and 1
    %   indicates 'good channel'. The default value is a vector of 1's.
    ChannelMap = ones(1, 37)

    %BLEChannelNumber BLE channel number
    %   Specify the BLE channel number as an integer value in the range [1,
    %   37]. It indicates the BLE channel number in which the packet is
    %   currently transmitting. The default value is 1.
    BLEChannelNumber = 1

    %OverallSuccessRate Over all success rate per channel
    %   Specify the overall success rate as an integer array of size 37 and
    %   each value should be in the range [0, 100]. It indicates overall
    %   success rate of the BLE data channels. The default value is a
    %   vector of 0's.
    OverallSuccessRate = zeros(1, 37)

    %WLANChannelList List of WLAN channels
    %   Specify the WLAN channel list as a vector of integers in the range
    %   [1, 14]. Each value indicates the WLAN channel number. The default
    %   value is 1.
    WLANChannelList = 1
    
    %ClassificationInterval Periodicity of channel classification
    %   Specify the classification interval as an integer in the range
    %   [100, 5000]. It defines the number of connection events after which
    %   channels will be classified and the updated channel map sent to all
    %   the connected Slaves from the Master. The default value is 148.
    ClassificationInterval = 148
    
    %PERThreshold Packet error rate (PER) threshold
    %   Specify the PER threshold as integer in the range of [60, 100]
    %   percentage. It is the threshold value of the packet error rate
    %   (PER) which is used to classify the channels. The default value is
    %   60.
    PERThreshold = 60
    
    %ChannelBusyCountThreshold Channel busy count threshold
    %   Specify the channel busy count threshold as integer in the range of
    %   [60, 100] percentage. It is the threshold value of channel busy
    %   count which is used to classify the channels. The default value is
    %   60.
    ChannelBusyCountThreshold = 60
    
    %PreferredMinimumGoodChannels Preferred number of good channels
    %   Specify the preferred minimum good channels as an integer in the
    %   range [2, 37]. This property indicates the preferred number of
    %   minimum good channels that need to be maintained for the BLE device
    %   operation. The default value is 2.
    PreferredMinimumGoodChannels = 2
    
    %ConnectionInterval Connection interval
    %   Specify the connection interval as an integer in the range [6,
    %   3200]. This property indicates the interval between the start of
    %   two consecutive connection events. Each unit is taken as 1.25 ms so
    %   that the resultant connection interval (ConnectionInterval*1.25) is
    %   in the range of 7.5 ms to 4.0 s. The default value is 6 (7.5 ms).
    ConnectionInterval = 6
    
    %Stoptime Simulation stop-time
    %   Specify the stop time as an integer indicating the simulation stop
    %   time in milliseconds. The default value is 0.
    Stoptime = 0
    
    %CurrentTime Current simulation time
    %   Specify the current time as an integer indicating current
    %   simulation time in milliseconds. The default value is 0.
    CurrentTime = 0
    
    %PHYMode Physical layer operating mode
    %   Specify the PHY mode as one of 'LE2M' | 'LE1M' | 'LE500K' |
    %   'LE125K'. It specifies the PHY rate index. The default value is ''.
    PHYMode = ''
    
    %RecentSuccessRate Success rate per data channel of the most recent
    %classification
    %   Specify the recent success rate as an integer array of size 37 and
    %   each value should be in the range [0, 100]. It indicates success
    %   rate of the BLE data channels in most recent classification. The
    %   default value is a vector of 0's.
    RecentSuccessRate = zeros(1, 37)
    
    %EnableVisualization Enable/disable the visualization
    %   Specify this flag as a logical scalar. A true value indicates that
    %   the visualization is enabled. The default value is true.
    EnableVisualization (1, 1) logical = true
    
    %EnableHoppingVisualization Enable/disable the visualization of channel
    %hopping sequence
    %   Specify this flag as a logical scalar. A true value indicates that
    %   the channel hopping sequence in the visualization is enabled. The
    %   default value is true.
    EnableHoppingVisualization (1, 1) logical = true
end

properties (Hidden, Constant)
    ActionValues = {'Initialize', 'Add WLAN channel',  ...
        'Remove WLAN channel', 'Active ble channel', ...
        'Update channel map', 'Failed to update channel map', ...
        'Corrupted ble channel', 'Simulation Progress', ...
        'Cumulative success rate'};
    
    PHYModeValues = {'LE2M', 'LE1M', 'LE500K', 'LE125K'};
end

properties(Hidden, Constant)
    % Constants used for the visualization
    
    % Start point of the figure
    PlotStartCoordinateX = 2;
    
    % BLE channel dimensions
    BLEChannelWidth = 3.2;
    BLEChannelHeight = 5;
    
    % Progress bar dimensions
    ProgressX = 0.85;
    ProgressY = 0.025;
    ProgressH = 0.02;
    ProgressW = 0.08;

    % Progress bar colors
    ProgressBarBackgroundColor = [0.9412, 0.9412, 0.9412];
    ProgressBarColor = [0.0235, 0.7412, 0.2510];
    
    % BLE and WLAN channel colors
    GoodChannelColor = '#d2e0b3';
    BadChannelColor = '#e5b5a5';
    CorruptedChannelColor = '#d95319';
    AdvertisingChannelColor = 'white';
    TransmittedChannelColor = '#77ac30';
    WLANChannelColor = [0 0.4471 0.7412 0.15];
    
    % Success rate colors
    RecentSuccessRateColor = '#99c7e5';
    OverallSuccessRateColor = '#0072bd';
end

properties (Access = private)
    pWLANChannelCoordinateY
    pChannelList
    pWLANChannels
    pWLANText
    pModelPlot
    pSuccessRatePlot
    pOverallSuccessRate
    pCoexistenceFigs
    pProgressInfo
    pPercentageInfo
    pStoptime
    pRecentSuccessRate
end

methods
    function obj = helperBLEVisualizeCoexistence(varargin)
        % Apply constructor name-value pairs:
        for idx = 1 : 2 : nargin
            obj.(varargin{idx}) = varargin{idx+1};
        end
    end

    % For auto completion:
    function v = set(obj, prop)
        v = obj.([prop, 'Values']);
    end

    function set.Action(obj, value)
        obj.Action = validatestring(value, obj.ActionValues, '', 'Action');
    end

    function set.WLANChannelIdx(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'integer', ...
            '>=', 1, '<=', 14}, '', 'WLANChannelIdx');
        obj.WLANChannelIdx = value;
    end

    function set.CollisionProbability(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'real', ...
            '>=', 0, '<=', 1}, '', 'CollisionProbability');
        obj.CollisionProbability = value;
    end

    function set.SlaveNumber(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'integer', ...
            '>=', 1, '<=', 5}, '', 'SlaveNumber');
        obj.SlaveNumber = value;
    end

    function set.SlaveCount(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'integer', ...
            '>=', 1, '<=', 5}, '', 'SlaveCount');
        obj.SlaveCount = value;
    end
    
    function set.ChannelMap(obj, value)
        validateattributes(value, {'numeric', 'logical'}, {'size', [1, 37], ...
            'binary'}, '', 'ChannelMap');
        obj.ChannelMap = value;
    end

    function set.BLEChannelNumber(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'integer', ...
            '>=', 1, '<=', 37}, '', 'BLEChannelNumber');
        obj.BLEChannelNumber = value;
    end

    function set.OverallSuccessRate(obj, value)
        validateattributes(value, {'numeric'}, {'size', [1, 37], 'integer', ...
            '>=', 0, '<=', 100}, '', 'OverallSuccessRate');
        obj.OverallSuccessRate = value;
    end

    function set.PHYMode(obj, value)
        obj.PHYMode = validatestring(value, obj.PHYModeValues, '', 'Action');
    end

    function initializeVisualization(obj)
    %initializeVisualization Initialize the BLE WLAN coexistence
    %visualization
    
        % Visualization is disabled
        if ~obj.EnableVisualization
            return;
        end
        
        % Get screen resolution
        resolution = get(0, 'screensize');
        screenWidth = resolution(3);
        screenHeight = resolution(4);
        
        % Progress bar dimensions
        progressDimension = [obj.ProgressX, obj.ProgressY, obj.ProgressW, obj.ProgressH];
        
        slavesCount = obj.SlaveCount;
        % Pre allocate for ble channels
        obj.pChannelList = cell(slavesCount, 40);
        obj.pCoexistenceFigs = cell(1, slavesCount);
        
        [obj.pWLANChannels, obj.pWLANText, obj.pModelPlot, obj.pSuccessRatePlot, ...
            obj.pOverallSuccessRate, obj.pProgressInfo, obj.pPercentageInfo, ...
            obj.pRecentSuccessRate] = deal(cell(slavesCount, 1));
        
        for k = 1:slavesCount
            % Initialize a figure for each Slave
            obj.pCoexistenceFigs{k} = figure('Name', ['Slave' num2str(k)], 'Position' , ...
                [screenWidth*0.1, screenHeight*(k*0.05), ...
                screenWidth*0.7, screenHeight*0.7], ...
                'MenuBar', 'none', 'Tag', ['CoexistenceWithoutPHY' num2str(k)]);
            
            coexistenceFigAxes = axes(obj.pCoexistenceFigs{k}, 'Visible', 'off');
            coexistenceFigAxes(2) = copyobj(coexistenceFigAxes(1), obj.pCoexistenceFigs{k});
            
            % Create a sub-plot for coexistence model visualization
            coexistenceFigAxes(1).Visible = 'Off';
            coexistenceFigAxes(1).Tag = ['CoexistenceWithoutPHYChannelHop' num2str(k)];

            obj.pModelPlot{k} = subplot(2, 1, 1, coexistenceFigAxes(1));
            obj.pModelPlot{k}.Position =  [0.20 0.5 0.78 0.5];
            obj.pModelPlot{k}.FontUnits = 'normalized';
            hold(coexistenceFigAxes(1), 'on');
            
            % Add annotation to the figure
            annotationDimensionBox = [0.004 0.68 0.3 0.3];
            annotationDimensionText = [0.035 0.678 0.3 0.3];
            
            % Advertising channel annotation string
            annotationString1 = {'Advertising channel'};
            annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                annotationDimensionText, 'String', annotationString1, ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTextbox' num2str(k)]);
            
            % WLAN channel annotation string
            annotationString2 = {'WLAN channel with'};
            annotationDimensionText(2) = annotationDimensionText(2)-0.027;
            annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                annotationDimensionText, 'String', annotationString2, ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTextbox' num2str(k)]);
            
            % WLAN channel annotation string
            annotationString3 = {'collision probability'};
            annotationDimensionText(2) = annotationDimensionText(2)-0.022;
            annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                annotationDimensionText, 'String', annotationString3, ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTextbox' num2str(k)]);
            
            % Good channel annotation string
            annotationString4 = {'Good channel'};
            annotationDimensionText(2) = annotationDimensionText(2)-0.028;
            annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                annotationDimensionText, 'String', annotationString4, ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTextbox' num2str(k)]);
            
            % Bad channel annotation string
            annotationString5 = {'Bad channel'};
            annotationDimensionText(2) = annotationDimensionText(2)-0.025;
            annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                annotationDimensionText, 'String', annotationString5, ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTextbox' num2str(k)]);
            
            % Transmission success annotation string
            annotationString6 = {'Transmission success'};
            annotationDimensionText(2) = annotationDimensionText(2)-0.025;
            annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                annotationDimensionText, 'String', annotationString6, ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTextbox' num2str(k)]);
            
            % Transmission failure annotation string
            annotationString7 = {'Transmission failure'};
            annotationDimensionText(2) = annotationDimensionText(2)-0.025;
            annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                annotationDimensionText, 'String', annotationString7, ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTextbox' num2str(k)]);
            
            % Channel annotation colors
            colorAnnotationDimension = [annotationDimensionBox(1)+0.01 ...
                annotationDimensionBox(2)+0.2725 0.020 0.014];
            annotation(obj.pCoexistenceFigs{k}, 'rectangle', colorAnnotationDimension,...
                'FaceColor', obj.AdvertisingChannelColor, 'Units', 'normalized', ...
                'Tag', ...
                ['CoexistenceWithoutPHYAnnotationAdvChannel' num2str(k)]);
            colorAnnotationDimension(2) = colorAnnotationDimension(2)-0.027;
            annotation(obj.pCoexistenceFigs{k}, 'rectangle', colorAnnotationDimension, ...
                'FaceColor', obj.WLANChannelColor, 'FaceAlpha', 0.15, ...
                'Units', 'normalized', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationWLANChannel' num2str(k)]);
            colorAnnotationDimension(2) = colorAnnotationDimension(2)-0.05;
            annotation(obj.pCoexistenceFigs{k}, 'rectangle', colorAnnotationDimension, ...
                'FaceColor', obj.GoodChannelColor, 'Units', 'normalized', ...
                'Tag', ...
                ['CoexistenceWithoutPHYAnnotationGoodChannel' num2str(k)]);
            colorAnnotationDimension(2) = colorAnnotationDimension(2)-0.025;
            annotation(obj.pCoexistenceFigs{k}, 'rectangle', colorAnnotationDimension, ...
                'FaceColor', obj.BadChannelColor, 'Units', 'normalized', ...
                'Tag', ...
                ['CoexistenceWithoutPHYAnnotationBadChannel' num2str(k)]);
            colorAnnotationDimension(2) = colorAnnotationDimension(2)-0.025;
            annotation(obj.pCoexistenceFigs{k}, 'rectangle', colorAnnotationDimension, ...
                'FaceColor', obj.TransmittedChannelColor, 'Units', 'normalized', ...
                'Tag', ...
                ['CoexistenceWithoutPHYAnnotationTransmittedChannel' num2str(k)]);
            colorAnnotationDimension(2) = colorAnnotationDimension(2)-0.025;
            annotation(obj.pCoexistenceFigs{k}, 'rectangle', colorAnnotationDimension, ...
                'FaceColor', obj.CorruptedChannelColor, 'Units', 'normalized', ...
                'Tag', ...
                ['CoexistenceWithoutPHYAnnotationCorruptedChannel' num2str(k)]);
            
            % Set axis limits
            axis(obj.pModelPlot{k}, [0 130 4 12]);
            axis(obj.pModelPlot{k}, 'off')
            
            % Initialize the ble channel coordinates
            nextBLEChannelCoordinateX = 2;
            nextBLEChannelCoordinateY = 2;
            lineX= [obj.PlotStartCoordinateX obj.PlotStartCoordinateX];
            lineY= [7 11];
            bleChannelText(1:40) = text(obj.pModelPlot{k});
            
            if isempty(obj.PHYMode)
                phyMode = '';
            else
                phyMode = [' (' obj.PHYMode ' PHY)'];
            end
            
            % Title for the model
            text(obj.pModelPlot{k}, 23, 11.5, ['2.4 GHz BLE and WLAN Coexistence Model' phyMode], ...
                'FontWeight', 'bold', 'FontSize', 16, 'FontUnits', 'normalized', ...
                'color', [0.5 0.2 0.6], 'Tag', 'CoexistenceWithoutPHYTitle');
            
            % Add BLE channels
            for idx = 1:40
                obj.pChannelList{k, idx} = rectangle(obj.pModelPlot{k}, 'Tag', ...
                    ['CoexistenceWithoutPHYChannelRectangle' num2str(idx)]);
                nextBLEChannelCoordinateX = ...
                    nextBLEChannelCoordinateX + obj.BLEChannelWidth;
                bleChannelCoordinateX = nextBLEChannelCoordinateX;
                
                % Re-order the BLE advertisement channels
                if (idx == 38)
                    bleChannelCoordinateX = obj.PlotStartCoordinateX;
                    color = obj.AdvertisingChannelColor;
                elseif(idx == 39)
                    bleChannelCoordinateX = obj.PlotStartCoordinateX+(12*obj.BLEChannelWidth);
                    color = obj.AdvertisingChannelColor;
                elseif(idx == 40)
                    bleChannelCoordinateX = obj.PlotStartCoordinateX+(39*obj.BLEChannelWidth);
                    color = obj.AdvertisingChannelColor;
                else
                    color = obj.GoodChannelColor;
                    % Channel index 11 is an advertisement channel, so the
                    % next channels will be shifted by one ble channel
                    % width
                    if(idx > 11)
                        bleChannelCoordinateX = bleChannelCoordinateX+obj.BLEChannelWidth;
                    end
                end
                obj.pChannelList{k, idx}.Position = [bleChannelCoordinateX ...
                    nextBLEChannelCoordinateY obj.BLEChannelWidth obj.BLEChannelHeight];
                obj.pChannelList{k, idx}.FaceColor = color;
                obj.pChannelList{k, idx}.Curvature = [1, 0.6];
                
                plot(obj.pModelPlot{k}, lineX, lineY, ':', 'color', [0.2 0.2 0.2], ...
                    'Tag', ['CoexistenceWithoutPHYChannelCurve' num2str(idx)]);
                lineX = lineX + obj.BLEChannelWidth;
                
                % Add channel number text to each BLE channel
                bleChannelText(idx) = text(obj.pModelPlot{k}, bleChannelCoordinateX+1.5, ...
                    nextBLEChannelCoordinateY+3.2, ['Channel-' num2str(idx-1)], ...
                    'color', 'k', 'Rotation', 90, 'HorizontalAlignment', 'center', ...
                    'FontUnits', 'normalized', 'Tag', ...
                    ['CoexistenceWithoutPHYChannelText' num2str(idx)]);
                
                % Show the center frequency of each BLE channel
                text(obj.pModelPlot{k}, nextBLEChannelCoordinateX-1.5, 3.2, ...
                    [num2str(2400 +idx*2), ' MHz'], 'color', 'k', 'Rotation', 90, ...
                    'HorizontalAlignment', 'center', 'FontUnits', 'normalized', ...
                    'Tag', ...
                    ['CoexistenceWithoutPHYChannelFrequency' num2str(idx)]);
            end
            
            text(obj.pModelPlot{k}, -5, 4, {['    Slave-', num2str(k)], 'Channel map'}, ...
                'FontWeight', 'bold', 'FontSize', 12, 'FontUnits', 'normalized', ...
                'color', [0.5 0.5 0.5], 'Rotation', 90, ...
                'Tag', ['CoexistenceWithoutPHYSlave' num2str(k)]);
            
            plot(obj.pModelPlot{k}, lineX, lineY, ':', 'color', [0.2 0.2 0.2], ...
                'Tag', ['CoexistenceWithoutPHYDashedLines' num2str(k)]);
            obj.pWLANChannelCoordinateY(k) = 7.5;
            
            % Create a sub-plot to plot the overall success rate per channel
            coexistenceFigAxes(2).Visible = 'On';
            coexistenceFigAxes(2).Tag = ['CoexistenceWithoutPHYSuccessRate' num2str(k)];
            obj.pSuccessRatePlot{k} = subplot(2, 1, 2, coexistenceFigAxes(2));
            obj.pSuccessRatePlot{k}.Position =  [0.20 0.1 0.78 0.28];
            obj.pSuccessRatePlot{k}.FontUnits = 'normalized';
            axis(obj.pSuccessRatePlot{k}, [0, 40, 0, 119])
            
            % Add labels to X and Y axes
            xlabel(obj.pSuccessRatePlot{k}, 'BLE Channel Number', ...
                'FontUnits', 'normalized', 'FontWeight', 'bold');
            ylabel(obj.pSuccessRatePlot{k}, 'Success Rate (%)', ...
                'FontUnits', 'normalized', 'FontWeight', 'bold');
            hold(coexistenceFigAxes(2), 'on');
            
            % Add title to the sub-plot
            text(obj.pSuccessRatePlot{k}, 12, 115, 'Success rate per channel', ...
                'FontWeight', 'bold', 'FontSize', 16, 'FontUnits', 'normalized', ...
                'color', [0.5 0.2 0.6], 'Tag', ...
                ['CoexistenceWithoutPHYSuccessRateTitle' num2str(k)]);
            obj.pRecentSuccessRate{k} = bar(obj.pSuccessRatePlot{k}, (0:39)+1.1, zeros(1, 40), ...
                'FaceColor', obj.RecentSuccessRateColor, 'Tag', ...
                ['CoexistenceWithoutPHYRecentSuccessrate' num2str(k)]);
            obj.pOverallSuccessRate{k} = bar(obj.pSuccessRatePlot{k}, ...
                (0:39)+0.8, zeros(1, 40), ...
                'FaceColor', obj.OverallSuccessRateColor, 'BarWidth', 0.3, 'Tag', ...
                ['CoexistenceWithoutPHYOverallSuccessrate' num2str(k)]);
            obj.pRecentSuccessRate{k}.BarWidth = 0.3;
            legend(obj.pSuccessRatePlot{k}, 'Recent success rate', ...
                'Cumulative success rate', ...
                'Tag', 'CoexistenceWithoutPHYLegend')
            xticks(coexistenceFigAxes(2), 0:40)
            xticklabels(coexistenceFigAxes(2), {'', '37', '0', '1', '2', '3', '4', '5', '6', '7', '8', ...
                '9', '10', '38', '11', '12', '13', '14', '15', '16', '17', '18', ...
                '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', ...
                '30', '31', '32', '33', '34', '35', '36', '39'});
            
            % Add progress bar
            annotation(obj.pCoexistenceFigs{k}, 'rectangle', progressDimension, ...
                'FaceColor', obj.ProgressBarBackgroundColor, 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationProgressBar' num2str(k)]);
            obj.pProgressInfo{k} = annotation(obj.pCoexistenceFigs{k}, 'rectangle', ...
                progressDimension, 'FaceColor', obj.ProgressBarColor, 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationProgress' num2str(k)]);
            obj.pProgressInfo{k}.Position(3) = 0;
            % Progress percentage display text
            obj.pPercentageInfo{k} = annotation(obj.pCoexistenceFigs{k}, 'textbox', ...
                progressDimension, 'String', '0%', ...
                'FitBoxToText', 'on', 'FontUnits', 'normalized', ...
                'LineStyle', 'none', 'HorizontalAlignment', 'center', ...
                'VerticalAlignment', 'middle', 'Tag', ...
                ['CoexistenceWithoutPHYAnnotationProgressText' num2str(k)]);
        end
    end
    
    function viewModel(obj)
        %viewModel Plots the coexistence model

        % Visualization is disabled
        if ~obj.EnableVisualization
            return;
        end
        
        wlanChannelWidth = 10*obj.BLEChannelWidth;
        wlanChannelHeight = 0.3;
        
        if strcmp(obj.Action, 'Remove WLAN channel')
            if ~isempty(obj.pChannelList)
                % Hide WLAN channels with blink effect

                channelIdx = obj.WLANChannelIdx;

                for idx = 1:3
                    pause(0.01); % To visualize the removal of WLAN channels
                    obj.pWLANChannels{obj.SlaveNumber}(channelIdx).Visible = 'on';
                    obj.pWLANText{obj.SlaveNumber}(channelIdx).Visible = 'on';
                    pause(0.01); % To visualize the removal of WLAN channels
                    obj.pWLANChannels{obj.SlaveNumber}(channelIdx).Visible = 'off';
                    obj.pWLANText{obj.SlaveNumber}(channelIdx).Visible = 'off';
                end
            end
            return;
        end

        if strcmp(obj.Action, 'Active ble channel')
            % Update success rate
            updateSuccessRate(obj);
            
            % Visualization of channel hopping sequence is enabled.
            if obj.EnableHoppingVisualization
                % Highlight the current BLE channel with a blink
                obj.pChannelList{obj.SlaveNumber, obj.BLEChannelNumber}.FaceColor = ...
                    obj.TransmittedChannelColor;
                pause(0.01) % To visualize the active BLE channel
                obj.pChannelList{obj.SlaveNumber, obj.BLEChannelNumber}.FaceColor = ...
                    obj.GoodChannelColor;
            end
            return;
        elseif strcmp(obj.Action, 'Corrupted ble channel')
            % Visualization of channel hopping sequence is enabled.
            if obj.EnableHoppingVisualization
                % Update success rate
                updateSuccessRate(obj);
            
                % Highlight the current BLE channel with a blink
                obj.pChannelList{obj.SlaveNumber, obj.BLEChannelNumber}.FaceColor = ...
                    obj.CorruptedChannelColor;
                pause(0.01); % To visualize the corrupted BLE channel
                obj.pChannelList{obj.SlaveNumber, obj.BLEChannelNumber}.FaceColor = ...
                    obj.GoodChannelColor;
            end
            return;
        elseif strcmp(obj.Action, 'Failed to update channel map')
            % Display the error message
            text(obj.pModelPlot{obj.SlaveNumber}, -5, 7.3, ...
                ['Master failed to send channel map update packet to Slave' ...
                ' because of the WLAN interference'], 'color', 'r', ...
                'FontWeight', 'bold', 'FontSize', 14, 'FontUnits', 'normalized');
            return;

        elseif strcmp(obj.Action, 'Add WLAN channel')
            channelIdx = obj.WLANChannelIdx;

            % Add a WLAN device to the figure
            wlanChannel = rectangle(obj.pModelPlot{obj.SlaveNumber}, 'Position', ...
                [obj.PlotStartCoordinateX+(obj.BLEChannelWidth/2)+((obj.WLANChannelList(channelIdx)-1)*obj.BLEChannelWidth*2.5) ...
                obj.pWLANChannelCoordinateY(obj.SlaveNumber) ...
                wlanChannelWidth wlanChannelHeight], 'FaceColor', ...
                obj.WLANChannelColor, 'Clipping', 'off');

            wlanChanPos = wlanChannel.Position;

            % Add channel number and collision probability text to the WLAN channel
            obj.pWLANText{obj.SlaveNumber}(channelIdx) = text(obj.pModelPlot{obj.SlaveNumber}, wlanChanPos(1)+6, wlanChanPos(2)+0.18, ...
                ['WLAN channel ' num2str(obj.WLANChannelList(channelIdx)) ' (' ...
                num2str(obj.CollisionProbability) ')'], ...
                'FontUnits', 'normalized', 'color', 'black');

            obj.pWLANChannelCoordinateY(obj.SlaveNumber) = ...
                obj.pWLANChannelCoordinateY(obj.SlaveNumber)+wlanChannelHeight+0.1;

            obj.pWLANChannels{obj.SlaveNumber}(channelIdx) = wlanChannel;

            % Add blink effect to the newly added WLAN channel
            for idx = 1:2
                pause(0.01); % To visualize the addition of WLAN Channels
                obj.pWLANChannels{obj.SlaveNumber}(channelIdx).Visible = 'off';
                obj.pWLANText{obj.SlaveNumber}(channelIdx).Visible = 'off';
                pause(0.01); % To visualize the addition of WLAN Channels
                obj.pWLANChannels{obj.SlaveNumber}(channelIdx).Visible = 'on';
                obj.pWLANText{obj.SlaveNumber}(channelIdx).Visible = 'on';
            end

        elseif strcmp(obj.Action, 'Update channel map')
            % Update success rate
            updateSuccessRate(obj);
            
            % Update channel map
            for idx = 1:numel(obj.ChannelMap)
                if ~obj.ChannelMap(idx)
                    obj.pChannelList{obj.SlaveNumber, idx}.FaceColor = obj.BadChannelColor;
                else
                    obj.pChannelList{obj.SlaveNumber, idx}.FaceColor = obj.GoodChannelColor;
                end
            end
            
        elseif strcmp(obj.Action, 'Simulation Progress')
            % Update simulation progress
            percentage = (obj.CurrentTime/obj.Stoptime)*100;
            obj.pProgressInfo{obj.SlaveNumber}.Position(3) = obj.ProgressW*(percentage/100);
            obj.pPercentageInfo{obj.SlaveNumber}.String = [ num2str(round(percentage)) '%'];
        end
    end
end

methods (Access = private)
    function updateSuccessRate(obj)
        %updateSuccessRate Update the recent and cumulative success rate of
        %the BLE channels
        
        % Update recent success rate in plot
        successRate = obj.RecentSuccessRate;
        successRate = [0 successRate(1:11) 0 successRate(12:end) 0];
        obj.pRecentSuccessRate{obj.SlaveNumber}.YData = successRate;
        
        % Update overall success rate in plot
        successRate = obj.OverallSuccessRate;
        successRate = [0 successRate(1:11) 0 successRate(12:end) 0];
        obj.pOverallSuccessRate{obj.SlaveNumber}.YData = successRate;
    end
end
end
