classdef helperBLEMeshLowPowerNode < handle
%helperBLEMeshLowPowerNode Create an object for Bluetooth mesh Low Power
%node
%   MESHLPN = helperBLEMeshLowPowerNode creates a Bluetooth mesh Low Power
%   node object, with properties and methods related to Low Power node.
%
%   MESHLPN = helperBLEMeshLowPowerNode(Name, Value) creates a Bluetooth
%   mesh Low Power node 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).
%
%   helperBLEMeshLowPowerNode property:
% 
%   FriendTimer  - Friend timer object
    
%   Copyright 2019 The MathWorks, Inc.

%#codegen

properties
    %FriendTimer Friend timer object
    %   Specify this property as an object of type <a
    %   href="matlab:help('helperBLEMeshFriendTimer')">helperBLEMeshFriendTimer</a>.
    %   Friend timer fields are populated using settings of this object.
    %   The default value is an object of type 'helperBLEMeshFriendTimer'
    %   with all properties set to their default values.
    FriendTimer
end
    
properties (Access = private)
    %pMD More Data flag indicates whether there are additional messages
    %queued at the Friend node for the Low Power node
    pMD (1, 1) logical = false
    
    %pFSN Friend Sequence Number, used to acknowledge receipt of previous
    %messages from the Friend node to the Low Power node
    pFSN = 0    
end

properties (Hidden, SetAccess = private)
    %pState Indicates the state of Low Power node
    %   0 - Sleep state
    %   1 - Listen state
    %   2 - Transmission state
    %   3 - Friendship termination state
    pState = 0
end

properties (SetAccess = private)
    %ListenTime Time for which the Low Power node is in listen state
    ListenTime = 0
    
    %SleepTime Time for which the Low Power node is in sleep state
    SleepTime = 0
    
    %TransmitToSleep Number of transitions from transmission to sleep state
    TransmitToSleep = 0
    
    %ListenToSleep Number of transitions from listen to sleep state
    ListenToSleep = 0
    
    %ListenToTransmit Number of transitions from listen to transmission
    %state
    ListenToTransmit = 0
    
    %SleepToTransmit Number of transitions from sleep to transmission state
    SleepToTransmit = 0
    
    %SleepToListen Number of transitions from sleep to listen state
    SleepToListen = 0
    
    %NResync Number of times Low Power node is re-synced with Friend node
    NResync = 0
end

methods
    function obj = helperBLEMeshLowPowerNode(varargin)
        % Name-value pairs
        for idx = 1:2:nargin
            obj.(char(varargin{idx})) = varargin{idx+1};
        end
        % Create a Bluetooth mesh friend timer object with default values
        obj.FriendTimer = helperBLEMeshFriendTimer();
    end
    
    % Set friend timer
    function set.FriendTimer(obj, value)
        validateattributes(value, {'helperBLEMeshFriendTimer'}, {'scalar'}, ...
            mfilename, 'FriendTimer');
        obj.FriendTimer = value;
    end
    
    % Provides an interface between Low Power feature and the transport
    % layer
    function [txMessage, txCtl] = run(obj, rxMessage, rxCtl)
        % Initialize
        txMessage = zeros(1, 0);
        txCtl = -1;
        
        % Reset rxCTL when Low Power node is not in listen state
        if (obj.pState ~= 1)
            rxCtl = -1;
        end
        
        previousState = obj.pState;
        obj.pState = obj.FriendTimer.runLPNTimer(rxCtl, obj.pMD);
        
        % Reset more data field when the receive timer reaches the sum of
        % receive delay and receive window
        if ~obj.FriendTimer.pReceiveFlag
            obj.pMD = 0;
        end
        
        % Transition from transmission to sleep state
        if previousState == 2 && obj.pState == 0
            obj.TransmitToSleep = obj.TransmitToSleep + 1;
        end
        
        % Transition from listen to sleep state
        if previousState == 1 && obj.pState == 0
            obj.ListenToSleep = obj.ListenToSleep + 1;
        end
        
        % Transition from listen to transmission state
        if previousState == 1 && obj.pState == 2
            obj.ListenToTransmit = obj.ListenToTransmit + 1;
        end
        
        % Transition from sleep to transmission state
        if previousState == 0 && obj.pState == 2
            obj.SleepToTransmit = obj.SleepToTransmit + 1;
        end
        
        % Transition from sleep to listen state
        if previousState == 0 && obj.pState == 1
            obj.SleepToListen = obj.SleepToListen + 1;
        end
        
        % Node state
        switch obj.pState
            % Sleep
            case 0
                % Update the sleep time
                obj.SleepTime = obj.SleepTime + obj.FriendTimer.StepTime;
            % Listen
            case 1
                % Update the listen time
                obj.ListenTime = obj.ListenTime + obj.FriendTimer.StepTime;
                
                % If the Low Power node receives a message in response to
                % friend poll message, it shall change the friend sequence
                % number. Refer Mesh Profile v1.0.1 of Bluetooth
                % Specification | Section 3.6.6.1
                if (~isempty(rxMessage)) && (rxCtl ~= -1)
                    % Toggle friend sequence number
                    obj.pFSN = double(~obj.pFSN);
                    % Low Power node receives friend update message
                    if rxCtl == 1
                        % Decode the friend update message
                        [~, obj.pMD] = ...
                        helperBLEMeshTransportControlMessageDecode(rxMessage);
                    end
                end
            % Transmission
            case 2
                % Send the friend poll message
                txMessage = helperBLEMeshTransportControlMessage('Friend poll', ...
                    obj.pFSN);
                txCtl = 1;
            % Terminate
            case 3
                % Update the re-sync count
                obj.NResync = obj.NResync + 1;
        end
    end
end
end
