function avgTimeStats = helperBLEMeshNodeAverageTime(meshNodes)
%helperBLEMeshNodeAverageTime Compute Bluetooth mesh nodes average time
%spent on various states
%   AVGTIMESTATS = helperBLEMeshNodeAverageTime(MESHNODES) computes the
%   average time spent on various states (transmit, listen, sleep and idle)
%   by different Bluetooth mesh nodes (Low Power, friend, relay and end
%   nodes) after running the Bluetooth mesh network simulation for
%   simulation time (in milliseconds).
%
%   AVGTIMESTATS returns the average time taken by different Bluetooth mesh
%   nodes in transmit, listen and sleep states in the table format.
% 
%   MESHNODES is a vector of objects of type helperBLEMeshNode.
%
%   This function generates a bar chart which compares the time taken in
%   transmit, listen and sleep states by different Bluetooth mesh nodes.
%   The results obtained from the bar chart concludes that Low Power node
%   is in sleep state for most of the time as compared with other Bluetooth
%   mesh nodes. Therefore, the Low Power node consumes less energy.

%   Copyright 2019 The MathWorks, Inc.

% Time taken to transmit a bit is 0.001 milliseconds with 1 Mbps bit rate
% (PHY mode: LE1M)
txTime = 0.001;

% Number of bits in an octet
octetLen = 8;
% Microseconds per millisecond
UsecPerMsec = 1e3;

% Initialize
nRelayNodes = 0;
nEndNodes = 0;
nFriendNodes = 0;
nLowPowerNodes = 0;
txTimeMeshNode = zeros(1, 4);
listenTimeMeshNode = zeros(1, 4);
sleepTimeMeshNode = zeros(1, 4);
idleTimeMeshNode = zeros(1, 4);
avgTxTimeMeshNode = zeros(1, 4);
avgListenTimeMeshNode = zeros(1, 4);
avgSleepTimeMeshNode = zeros(1, 4);
avgIdleTimeMeshNode = zeros(1, 4);
txBytesEnd = 0;
txBytesLPN = 0;

for nodeIdx = 1:numel(meshNodes)
    % The node is in Bluetooth mesh network
    if strcmpi(meshNodes(nodeIdx).State, 'On')
        % Bluetooth mesh node is a relay node
        if meshNodes(nodeIdx).NetworkLayer.Relay == 1
            if strcmpi(meshNodes(nodeIdx).TransportLayer.Feature, 'None')
                nRelayNodes = nRelayNodes + 1;
                txTimeMeshNode(1) = txTimeMeshNode(1) + ...
                    meshNodes(nodeIdx).LLGAPBearer.BytesTransmitted*octetLen*txTime;
                listenTimeMeshNode(1) = listenTimeMeshNode(1) + ...
                    meshNodes(nodeIdx).LLGAPBearer.ListenTime;
                sleepTimeMeshNode(1) = sleepTimeMeshNode(1) + ...
                    meshNodes(nodeIdx).LLGAPBearer.SleepTime;
                idleTimeMeshNode(1) = idleTimeMeshNode(1) + ...
                    meshNodes(nodeIdx).LLGAPBearer.IdleTime;
            end
        else
            % Bluetooth mesh node is an end node
            if ~strcmpi(meshNodes(nodeIdx).TransportLayer.Feature, 'Low power')
                nEndNodes = nEndNodes + 1;
                txTimeMeshNode(2) = txTimeMeshNode(2) + ...
                    meshNodes(nodeIdx).LLGAPBearer.BytesTransmitted*octetLen*txTime;
                txBytesEnd = txBytesEnd + meshNodes(nodeIdx).LLGAPBearer.BytesTransmitted;
                listenTimeMeshNode(2) = listenTimeMeshNode(2) + ...
                    meshNodes(nodeIdx).LLGAPBearer.ListenTime;
                sleepTimeMeshNode(2) = sleepTimeMeshNode(2) + ...
                    meshNodes(nodeIdx).LLGAPBearer.SleepTime;
                idleTimeMeshNode(2) = idleTimeMeshNode(2) + ...
                    meshNodes(nodeIdx).LLGAPBearer.IdleTime;
            end
        end
        % Bluetooth mesh node is a Friend node
        if strcmpi(meshNodes(nodeIdx).TransportLayer.Feature, 'Friend')
            nFriendNodes = nFriendNodes + 1;
            txTimeMeshNode(3) = txTimeMeshNode(3) + ...
                meshNodes(nodeIdx).LLGAPBearer.BytesTransmitted*octetLen*txTime;
            listenTimeMeshNode(3) = listenTimeMeshNode(3) + ...
                meshNodes(nodeIdx).LLGAPBearer.ListenTime;
            sleepTimeMeshNode(3) = sleepTimeMeshNode(3) + ...
                meshNodes(nodeIdx).LLGAPBearer.SleepTime;
            idleTimeMeshNode(3) = idleTimeMeshNode(3) + ...
                meshNodes(nodeIdx).LLGAPBearer.IdleTime;
        % Bluetooth mesh node is a Low Power node
        elseif strcmpi(meshNodes(nodeIdx).TransportLayer.Feature, 'Low power')
            nLowPowerNodes = nLowPowerNodes + 1;
            txTimeMeshNode(4) = txTimeMeshNode(4) + ...
                meshNodes(nodeIdx).LLGAPBearer.BytesTransmitted*octetLen*txTime;
            txBytesLPN = txBytesLPN + meshNodes(nodeIdx).LLGAPBearer.BytesTransmitted;
            listenTimeMeshNode(4) = listenTimeMeshNode(4) + ...
                meshNodes(nodeIdx).LLGAPBearer.ListenTime;
            sleepTimeMeshNode(4) = sleepTimeMeshNode(4) + ...
                meshNodes(nodeIdx).LLGAPBearer.SleepTime;
            idleTimeMeshNode(4) = idleTimeMeshNode(4) + ...
                meshNodes(nodeIdx).LLGAPBearer.IdleTime;
        end   
    end      
end


% Calculate the average time statistics of relay nodes
avgTxTimeMeshNode(1) = txTimeMeshNode(1)/nRelayNodes;
avgListenTimeMeshNode(1) = listenTimeMeshNode(1)/nRelayNodes;
avgSleepTimeMeshNode(1) = sleepTimeMeshNode(1)/nRelayNodes;
avgIdleTimeMeshNode(1) = idleTimeMeshNode(1)/nRelayNodes;

% Calculate the average time statistics of end nodes
avgTxTimeMeshNode(2) = txTimeMeshNode(2)/nEndNodes;
avgListenTimeMeshNode(2) = listenTimeMeshNode(2)/nEndNodes;
avgSleepTimeMeshNode(2) = sleepTimeMeshNode(2)/nEndNodes;
avgIdleTimeMeshNode(2) = idleTimeMeshNode(2)/nEndNodes;

% Calculate the average time statistics of Friend nodes
avgTxTimeMeshNode(3) = txTimeMeshNode(3)/nFriendNodes;
avgListenTimeMeshNode(3) = listenTimeMeshNode(3)/nFriendNodes;
avgSleepTimeMeshNode(3) = sleepTimeMeshNode(3)/nFriendNodes;
avgIdleTimeMeshNode(3) = idleTimeMeshNode(3)/nFriendNodes;

% Calculate the average time statistics of Low Power nodes
avgTxTimeMeshNode(4) = txTimeMeshNode(4)/nLowPowerNodes;
avgListenTimeMeshNode(4) = listenTimeMeshNode(4)/nLowPowerNodes;
avgSleepTimeMeshNode(4) = sleepTimeMeshNode(4)/nLowPowerNodes;
avgIdleTimeMeshNode(4) = idleTimeMeshNode(4)/nLowPowerNodes;


% Variables needed to display average time statistics in bar chart
timeStatsRelayNode = [avgTxTimeMeshNode(1) avgListenTimeMeshNode(1)/UsecPerMsec ...
    avgIdleTimeMeshNode(1)/UsecPerMsec avgSleepTimeMeshNode(1)/UsecPerMsec];
timeStatsEndNode = [avgTxTimeMeshNode(2) avgListenTimeMeshNode(2)/UsecPerMsec ...
    avgIdleTimeMeshNode(2)/UsecPerMsec avgSleepTimeMeshNode(2)/UsecPerMsec];
timeStatsFriendNode = [avgTxTimeMeshNode(3) avgListenTimeMeshNode(3)/UsecPerMsec ...
    avgIdleTimeMeshNode(3)/UsecPerMsec avgSleepTimeMeshNode(3)/UsecPerMsec];
timeStatsLowPowerNode = [avgTxTimeMeshNode(4) avgListenTimeMeshNode(4)/UsecPerMsec ...
    avgIdleTimeMeshNode(4)/UsecPerMsec avgSleepTimeMeshNode(4)/UsecPerMsec];

nodeTypes  = categorical({'Low Power node'; 'Friend node'; 'Relay node'; 'End node'});
statisticsAtNode = [timeStatsLowPowerNode; timeStatsFriendNode; ...
    timeStatsRelayNode; timeStatsEndNode];

avgTimeStatsPlot = figure;
avgTimeStatsPlot.Name = 'Average time statistics of different Bluetooth mesh nodes';
avgTimePlotAxes = axes(avgTimeStatsPlot);
bar(avgTimePlotAxes, nodeTypes, statisticsAtNode/UsecPerMsec);
avgTimeStatsPlot.CurrentAxes.Box = 'off';
avgTimePlotAxes.YScale = 'log';
ylabel(avgTimePlotAxes, 'Average time (sec)');
title(avgTimePlotAxes, 'Average time statistics of different Bluetooth mesh nodes');
legend(avgTimePlotAxes, 'Transmission', 'Listen', 'Idle', 'Sleep', ...
    'Location', 'northeastoutside');

% Variables needed to display average time statistics in table format
avgTxTime = [timeStatsLowPowerNode(1); timeStatsFriendNode(1); ...
    timeStatsRelayNode(1); timeStatsEndNode(1)];
avgListenTime = [timeStatsLowPowerNode(2); timeStatsFriendNode(2); ...
    timeStatsRelayNode(2); timeStatsEndNode(2)];
avgIdleTime = [timeStatsLowPowerNode(3); timeStatsFriendNode(3); ...
    timeStatsRelayNode(3); timeStatsEndNode(3)];
avgSleepTime = [timeStatsLowPowerNode(4); timeStatsFriendNode(4); ...
    timeStatsRelayNode(4); timeStatsEndNode(4)];

% Display of average time taken by different Bluetooth mesh nodes in
% transmission, listen and sleep states
avgTimeStats = table(nodeTypes, avgTxTime, avgListenTime, avgIdleTime, avgSleepTime, ...
    'VariableNames', {'Type of Bluetooth mesh node'; 'Transmission time (milliseconds)'; ...
    'Listen time (milliseconds)'; 'Idle time (milliseconds)'; 'Sleep time (milliseconds)'});
end
