classdef bluetoothMeshProfileConfig < comm.internal.ConfigBase
    %bluetoothMeshProfileConfig Bluetooth mesh profile configuration
    %parameters
    %
    %   MESHCONFIG = bluetoothMeshProfileConfig creates a default
    %   Bluetooth(R) mesh profile configuration object. This object
    %   specifies the mesh profile properties of the Bluetooth low energy
    %   (LE) node.
    %
    %   MESHCONFIG = bluetoothMeshProfileConfig(Name=Value) creates a
    %   Bluetooth mesh profile configuration object, MESHCONFIG, with the
    %   specified property Name set to the specified Value. You can specify
    %   additional name-value arguments in any order as (Name1=Value1, ...,
    %   NameN=ValueN).
    %
    %   bluetoothMeshProfileConfig properties:
    %
    %   ElementAddress          - Unicast address of the element
    %   Relay                   - Support for relay feature
    %   Friend                  - Support for friend feature
    %   LowPower                - Support for low power feature
    %   NetworkTransmissions    - Number of network transmissions
    %   NetworkTransmitInterval - Time interval between consecutive network
    %                             transmissions, in seconds
    %   TTL                     - Time to live (TTL) for the message
    %   RelayRetransmissions    - Number of relay retransmissions
    %   RelayRetransmitInterval - Time interval between consecutive relay
    %                             retransmissions, in seconds
    %
    %   % Example 1:
    %   % Create Bluetooth mesh profile configuration object
    %   meshCfg = bluetoothMeshProfileConfig
    %
    %   % Example 2:
    %   % Check if the Communications Toolbox(TM) Wireless Network Simulation
    %   % Library support package is installed. If the support package is not
    %   % installed, MATLAB(R) returns an error with a link to download and install
    %   % the support package.
    %   wirelessnetworkSupportPackageCheck
    %
    %   % Create a Bluetooth mesh relay node having a single element with
    %   % unicast address "0001". Set the network layer transmissions to 3,
    %   % advertising interval to 30 milliseconds, and scan interval to 20
    %   % milliseconds.
    %
    %   % Create and configure mesh profile configuration object
    %   meshCfg = bluetoothMeshProfileConfig;
    %   meshCfg.ElementAddress = "0001";
    %   meshCfg.Relay = true;
    %   meshCfg.NetworkTransmissions = 3;
    %
    %   % Create a Bluetooth LE mesh node with the specified properties
    %   meshNode = bluetoothLENode("broadcaster-observer",...
    %                              MeshConfig=meshCfg,...
    %                              AdvertisingInterval=0.03,...
    %                              ScanInterval=0.02,...
    %                              Name="SampleRelayNode",...
    %                              Position=[0 0 0]); % In meters
    %
    %   See also bluetoothMeshFriendshipConfig, bluetoothLENode,
    %   bluetoothLEConnectionConfig, bluetoothLEBIGConfig.

    %   Copyright 2021-2023 The MathWorks, Inc.

    properties
        %ElementAddress Unicast address of the element
        %   Specify the element address as a 4-element character vector or
        %   string scalar denoting a 2-octet hexadecimal unicast address.
        %   If the mesh profile has multiple elements, specify this value
        %   as a char vector of size N-by-4 or a string vector of size N,
        %   where N is the total number of elements in the mesh profile.
        %   The value of this property must be unique for each node in the
        %   mesh network. For more information about the element address,
        %   see Bluetooth mesh profile v1.0.1, section 2.3.4. The default
        %   value is "0001".
        ElementAddress = "0001"

        %Relay Support for relay feature
        %   Specify the relay as a logical 1 (true) or 0 (false). A true
        %   value indicates that the object supports and enables the relay
        %   feature at the network layer of the mesh profile. For more
        %   information about the Relay feature, see Bluetooth mesh profile
        %   v1.0.1, section 2.3.11. The default value is false.
        Relay (1, 1) logical = false

        %Friend Support for friend feature
        %   Specify the friend as a logical 1 (true) or 0 (false). A true
        %   value indicates that the object supports and enables the friend
        %   feature at the transport layer of the mesh profile. For more
        %   information about the Friend feature, see Bluetooth mesh
        %   profile v1.0.1, section 2.3.11. The default value is false.
        Friend (1, 1) logical = false

        %LowPower Support for low power feature
        %   Specify the low power as a logical 1 (true) or 0 (false). A
        %   true value indicates that the object supports and enables the
        %   low power feature at the transport layer of the mesh profile.
        %   For more information about the LowPower feature, see Bluetooth
        %   mesh profile v1.0.1, section 2.3.11. The default value is
        %   false.
        LowPower (1, 1) logical = false

        %NetworkTransmissions Number of network transmissions
        %   Specify the network transmissions as an integer in the range
        %   [1, 8]. This value specifies the number of times a node
        %   transmits the network message. For more information about the
        %   NetworkTransmissions value, see Bluetooth mesh profile v1.0.1,
        %   section 4.2.19.1. The default value is 1
        NetworkTransmissions (1,1) {mustBeInteger, ...
            mustBeGreaterThanOrEqual(NetworkTransmissions,1), ...
            mustBeLessThanOrEqual(NetworkTransmissions,8)} = 1

        %NetworkTransmitInterval Time interval between consecutive network
        %transmissions, in seconds
        %   Specify the network transmit interval as a scalar in the range
        %   [0.01, 0.320]. Units are in seconds. This value specifies the
        %   time interval between the consecutive network messages that the
        %   node transmits. Set this value as an integer multiple of 10
        %   milliseconds. For more information about the
        %   NetworkTransmitInterval value, see Bluetooth mesh profile
        %   v1.0.1, section 4.2.19.2. The default value is 0.01.
        NetworkTransmitInterval = 0.01

        %TTL Time to live (TTL) for the message
        %   Specify the TTL as an integer in the range [0, 127], excluding
        %   1. This value specifies the maximum number of hops that the
        %   transmitted message can traverse. When the higher layers of the
        %   mesh profile fail to set the TTL value for the transmitted
        %   message, the object uses this value in the generated network
        %   message. For more information about the TTL value, see
        %   Bluetooth mesh profile v1.0.1, section 4.2.7. The default value
        %   is 127.
        TTL = 127

        %RelayRetransmissions Number of relay retransmissions
        %   Specify the relay retransmissions as an integer in the range
        %   [1, 8]. This value shows the number of times a node retransmits
        %   a relayed network message. For more information about the
        %   RelayRetransmissions value, see Bluetooth mesh profile v1.0.1,
        %   section 4.2.20.1. The default value is 1.
        RelayRetransmissions (1,1) {mustBeInteger, ...
            mustBeGreaterThanOrEqual(RelayRetransmissions,1), ...
            mustBeLessThanOrEqual(RelayRetransmissions,8)} = 1

        %RelayRetransmitInterval Time interval between consecutive relay
        %retransmissions, in seconds
        %   Specify the relay retransmit interval as a scalar in the range
        %   [0.01, 0.320]. Units are in seconds. This value specifies the
        %   time interval between the consecutive relayed messages that the
        %   node retransmits. Set this value as an integer multiple of 10
        %   milliseconds. For more information about the
        %   RelayRetransmitInterval value, see Bluetooth mesh profile
        %   v1.0.1, section 4.2.20.2. The default value is 0.01.
        RelayRetransmitInterval = 0.01
    end

    methods
        function obj = bluetoothMeshProfileConfig(varargin)
            obj@comm.internal.ConfigBase(varargin{:});
        end

        function obj = set.ElementAddress(obj, value)
            numElements = size(value, 1);
            if numElements > 1
                charValue = char(zeros(numElements, 4));
                for idx = 1:numElements
                    ble.internal.validateHex(value(idx, :), 4, "ElementAddress");
                    validateUnicastAddress(obj, value(idx, :));
                    charValue(idx, :) = value(idx, :);
                end
            else
                ble.internal.validateHex(value, 4, "ElementAddress");
                validateUnicastAddress(obj, value);
                charValue = convertStringsToChars(value);
            end
            initValue = charValue;
            coder.varsize("initValue");
            obj.ElementAddress = string(initValue);
        end

        function obj = set.Relay(obj, value)
            validateProfileFeatures(obj, "Relay", value);
            obj.Relay = value;
        end

        function obj = set.Friend(obj, value)
            validateProfileFeatures(obj, "Friend", value);
            obj.Friend = value;
        end

        function obj = set.LowPower(obj, value)
            validateProfileFeatures(obj, "LowPower", value);
            obj.LowPower = value;
        end

        function obj = set.TTL(obj, value)
            % TTL value 1 is invalid. Refer Bluetooth mesh profile v1.0.1,
            % section 4.2.7
            coder.internal.errorIf((value == 1), ...
                "bluetooth:bluetoothLENode:InvalidTTL", value);
            validateattributes(value, {'numeric'}, {'scalar', ...
                'integer', '>=', 0, '<=', 127}, mfilename, "TTL");
            obj.TTL = value;
        end

        function obj = set.NetworkTransmitInterval(obj, value)
            validateattributes(value, {'numeric'}, {'scalar', '>=', 0.01, ...
                '<=', 0.320}, mfilename, "NetworkTransmitInterval");
            coder.internal.errorIf((mod(value, 0.01) ~= 0), ...
                "bluetooth:bluetoothLENode:InvalidNetworkTransmitInterval", num2str(value));
            obj.NetworkTransmitInterval = value;
        end

        function obj = set.RelayRetransmitInterval(obj, value)
            validateattributes(value, {'numeric'}, {'scalar', '>=', 0.01, ...
                '<=', 0.320}, mfilename, "RelayRetransmitInterval");
            coder.internal.errorIf((mod(value, 0.01) ~= 0), ...
                "bluetooth:bluetoothLENode:InvalidRelayRetransmitInterval", num2str(value));
            obj.RelayRetransmitInterval = value;
        end
    end

    methods (Access = protected)
        function flag = isInactiveProperty(obj, prop)
            flag = true;

            % Applicable for all features
            if any(strcmp(prop, {'ElementAddress', 'Relay', 'Friend', 'TTL', ...
                    'LowPower', 'NetworkTransmissions' 'NetworkTransmitInterval'}))
                flag = false;
                return;
            end

            % Applicable for Relay feature
            if any(strcmp(prop, {'RelayRetransmissions', ...
                    'RelayRetransmitInterval'})) && obj.Relay
                flag = false;
                return;
            end
        end
    end

    methods (Access = private)
        function validateUnicastAddress(~, address)
            % Refer Bluetooth mesh profile v1.0.1, section 3.4.2.1
            addressBinary = int2bit(hex2dec(address), 16);
            coder.internal.errorIf((...
                ~(addressBinary(1) == 0 && sum(addressBinary) ~= 0)), ...
                "bluetooth:bluetoothLENode:InvalidElementAddress");
        end

        function validateProfileFeatures(obj, param, value)
            % LowPower feature cannot be enabled, when Friend feature or
            % Relay feature or both were enabled.
            switch param
                case "Relay"
                    coder.internal.errorIf(obj.LowPower && value == 1, ...
                        "bluetooth:bluetoothLENode:InvalidRelayFeature");
                case "Friend"
                    coder.internal.errorIf(obj.LowPower && value == 1, ...
                        "bluetooth:bluetoothLENode:InvalidFriendFeature");
                case "LowPower"
                    coder.internal.errorIf((obj.Friend || obj.Relay) && value == 1, ...
                        "bluetooth:bluetoothLENode:InvalidLowPowerFeature");
            end
        end
    end
end
