classdef bleLLAdvertisingChannelPDUConfig < comm.internal.ConfigBase
%bleLLAdvertisingChannelPDUConfig Bluetooth LE LL advertising channel PDU
%configuration parameters
%   CFGLLADV = bleLLAdvertisingChannelPDUConfig creates a default
%   Bluetooth(R) low energy (LE) advertising channel protocol data unit
%   (PDU) configuration object.
%
%   CFGLLADV = bleLLAdvertisingChannelPDUConfig(Name, Value) creates a
%   Bluetooth LE advertising channel PDU configuration object, CFGLLADV,
%   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).
%
%   bleLLAdvertisingChannelPDUConfig properties:
%
%   PDUType               - Advertising channel PDU type
%   ChannelSelection      - Channel selection algorithm
%   AdvertiserAddressType - Advertiser device address type
%   AdvertiserAddress     - Advertiser device address
%   TargetAddressType     - Target device address type
%   TargetAddress         - Target device address
%   ScannerAddressType    - Scanner device address type
%   ScannerAddress        - Scanner device address
%   InitiatorAddressType  - Initiator device address type
%   InitiatorAddress      - Initiator device address
%   AdvertisingData       - Advertising data
%   ScanResponseData      - Scan response data
%   AccessAddress         - Unique connection address
%   CRCInitialization     - CRC initialization value
%   WindowSize            - Transmit window size
%   WindowOffset          - Transmit window offset
%   ConnectionInterval    - Connection interval
%   PeripheralLatency     - Peripheral latency
%   ConnectionTimeout     - Connection supervision timeout
%   UsedChannels          - List of used (good) data channels
%   HopIncrement          - Hop increment count
%   SleepClockAccuracy    - Central sleep clock accuracy
%
%   % Example 1:
%   % Create a bleLLAdvertisingChannelPDUConfig object for an advertising
%   % channel PDU by assigning PDUType to 'Advertising indication' with
%   % advertising data set as "020106".
%
%   cfgLLAdv = bleLLAdvertisingChannelPDUConfig;
%   cfgLLAdv.PDUType         = 'Advertising indication';
%   cfgLLAdv.AdvertisingData = "020106"
%
%   % Example 2:
%   % Create a bleLLAdvertisingChannelPDUConfig object for a
%   % 'Scan response' PDU with scan response data '020106020AD3'.
%
%   cfgLLAdv = bleLLAdvertisingChannelPDUConfig(...
%                             'PDUType', 'Scan response', ...
%                             'AdvertiserAddress', '1234567890AB', ...
%                             'ScanResponseData', '020106020AD3')
%
%   % Example 3:
%   % Create a bleLLAdvertisingChannelPDUConfig object for
%   % a 'Connection indication' PDU with connection interval set to
%   % 64 (80 ms, each unit is taken as 1.25 ms) and used channels set as
%   % '[0 4 12 16 18 24 25]'.
%
%   cfgLLAdv = bleLLAdvertisingChannelPDUConfig('PDUType', ...
%                                             'Connection indication');
%   cfgLLAdv.ConnectionInterval = 64;
%   cfgLLAdv.UsedChannels       = [0 4 12 16 18 24 25]
%
%   % Example 4:
%   % Link Layer advertising channel PDUs end-to-end workflow.
%
%   % Tx side
%   % Create a bleLLAdvertisingChannelPDUConfig object for an advertising
%   % channel PDU of type 'Connection indication'.
%   cfgTx = bleLLAdvertisingChannelPDUConfig('PDUType', ...
%                                               'Connection indication');
%   cfgTx.ConnectionInterval = 8;
%   cfgTx.UsedChannels       = [0 4 12 16 18 24 25]
%   %  Generate an advertising channel PDU using 'cfgTx'.
%   pdu = bleLLAdvertisingChannelPDU(cfgTx);
%
%   % Rx side
%   % Decode a Link Layer advertising channel PDU.
%   [status, cfgRx] = bleLLAdvertisingChannelPDUDecode(pdu);
%   if strcmp(status, 'Success') % Decoding is successful
%       cfgRx
%   else
%       fprintf('Link Layer decoding status ::');
%       status
%   end
%
%   See also bleLLAdvertisingChannelPDU, bleLLAdvertisingChannelPDUDecode.

%   Copyright 2018-2022 The MathWorks, Inc.

%#codegen

properties
    %PDUType Advertising channel PDU type
    %   Specify the PDU type as one of 'Advertising indication' |
    %   'Advertising direct indication' |'Advertising non connectable
    %   indication' | 'Scan request' | 'Scan response' | 'Connection
    %   indication' | ' Advertising scannable indication'. This property
    %   indicates the type of advertising channel PDU. The default value is
    %   'Advertising indication'.
    PDUType
    
    %ChannelSelection Channel Selection Algorithm
    %   Specify the channel selection as one of 'Algorithm1' |
    %   'Algorithm2'. This property indicates the algorithm used for
    %   hopping between channels. The default value is 'Algorithm1'.
    ChannelSelection = 'Algorithm1'
    
    %AdvertiserAddressType Advertiser device address type
    %   Specify the advertiser address type as one of 'Public' | 'Random'.
    %   This property indicates the type of advertiser address in the
    %   packet. The default value is 'Random'.
    AdvertiserAddressType = 'Random'
    
    %AdvertiserAddress Advertiser device address
    %   Specify the advertiser address as a 12-element character vector or
    %   string scalar denoting a 6-octet hexadecimal value. This property
    %   indicates the advertiser device address. The default value is
    %   '0123456789AB'.
    AdvertiserAddress = '0123456789AB'
    
    %TargetAddressType Target device address type
    %   Specify the target address type as one of 'Public' | 'Random'. This
    %   property indicates the type of target device address when a
    %   directed advertisement packet is transmitted. The default value is
    %   'Random'.
    TargetAddressType = 'Random'
    
    %TargetAddress Target device address
    %   Specify the target address as a 12-element character vector or
    %   string scalar denoting a 6-octet hexadecimal value. This property
    %   indicates the target device address when a directed advertisement
    %   packet is transmitted. The default value is '0123456789CD'.
    TargetAddress = '0123456789CD'
    
    %ScannerAddressType Scanner device address type
    %   Specify the scanner address type as one of 'Public' | 'Random'.
    %   This property indicates the type of scanner device address when a
    %   scan request packet is transmitted. The default value is 'Random'.
    ScannerAddressType = 'Random'
    
    %ScannerAddress Scanner device address
    %   Specify the scanner address as a 12-element character vector or
    %   string scalar denoting a 6-octet hexadecimal value. This property
    %   indicates the scanner device address when a scan request packet is
    %   transmitted. The default value is '0123456789CD'.
    ScannerAddress = '0123456789CD'
    
    %InitiatorAddressType Initiator device address type
    %   Specify the initiator address type as one of 'Public' | 'Random'.
    %   This property indicates the type of initiator device address when a
    %   connection indication packet is transmitted. The default value is
    %   'Random'.
    InitiatorAddressType = 'Random'
    
    %InitiatorAddress Initiator device address
    %   Specify the initiator address as a 12-element character vector or
    %   string scalar denoting a 6-octet hexadecimal value. This property
    %   indicates the initiator device address when a connection indication
    %   packet is transmitted. The default value is '0123456789CD'.
    InitiatorAddress = '0123456789CD'
    
    %AdvertisingData Advertising data
    %   Specify the advertising data as a string or character vector or
    %   n-by-2 character array (LSB first) of hexadecimal octets. It can
    %   also be specified as a numeric vector of decimal octets. Length of
    %   the advertising data must be in the range of [0, 31] octets. This
    %   property indicates the advertising data that the device sends out
    %   in an advertisement packet. The default value is an '020106'.
    AdvertisingData
    
    %ScanResponseData Scan response data
    %   Specify the scan response data as a string or character vector or
    %   n-by-2 character array (LSB first) of hexadecimal octets. It can
    %   also be specified as a numeric vector of decimal octets. Length of
    %   the scan response data must be in the range of [0, 31] octets. This
    %   property indicates the scan response data that the device sends out
    %   in a scan response packet (when scan request is received). The
    %   default value is '020106'.
    ScanResponseData
    
    %AccessAddress Unique connection address
    %   Specify the access address as a 8-element character vector or
    %   string scalar denoting a 4-octet hexadecimal value. This property
    %   indicates a unique 32-bit address generated by the Link Layer for
    %   the new connection or for a periodic advertisement between two
    %   devices. The default value is '01234567'.
    AccessAddress = '01234567'
    
    %CRCInitialization CRC initialization value
    %   Specify the CRC initialization as a 6-element character vector or
    %   string scalar denoting a 3-octet hexadecimal value. This property
    %   is used as initialization value for the CRC calculation. The
    %   default value is '012345'.
    CRCInitialization = '012345'
    
    %WindowSize Transmit window size
    %   Specify the window size as an integer in the range [1, Mws], where
    %   Mws is the lesser of 8 and (<a
    %   href="matlab:help('bleLLAdvertisingChannelPDUConfig.ConnectionInterval')">ConnectionInterval</a>-1).
    %   This property indicates the window size within which the Central
    %   transmits the data packet and Peripheral listens for the data
    %   packet after connection establishment. Each unit is taken as 1.25
    %   ms so that the resultant window size (WindowSize*1.25) is in the
    %   range of 1.25 ms to the minimum of (10 ms,
    %   ((ConnectionInterval*1.25) - 1.25) ms). The default value is 1.
    WindowSize = 1
    
    %WindowOffset Transmit window offset
    %   Specify the window offset as an integer in the range [0, Mwo],
    %   where Mwo is the lesser of 3200 and <a
    %   href="matlab:help('bleLLAdvertisingChannelPDUConfig.ConnectionInterval')">ConnectionInterval</a>.
    %   This property indicates the window offset after which the transmit
    %   window starts. Each unit is taken as 1.25 ms so that the resultant
    %   window offset (WindowOffset*1.25) is in the range of 0 ms to
    %   (ConnectionInterval*1.25) ms. The default value is 0.
    WindowOffset = 0
    
    %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
    
    %PeripheralLatency Peripheral latency
    %   Specify the Peripheral latency as an integer in the range [0, Msl],
    %   where Msl is the lesser of 499 and ((<a
    %   href="matlab:help('bleLLAdvertisingChannelPDUConfig.ConnectionTimeout')">ConnectionTimeout</a>*10)/((<a
    %   href="matlab:help('bleLLAdvertisingChannelPDUConfig.ConnectionInterval')">ConnectionInterval</a>*1.25)*2))-1.
    %   This property indicates the number of connection events that a
    %   Peripheral might skip listening for packets from the Central. The
    %   default value is 0.
    PeripheralLatency = 0
    
    %ConnectionTimeout Connection supervision timeout
    %   Specify the connection timeout as an integer in the range [Mct,
    %   3200], where Mct is the larger of 10 and ((1+<a
    %   href="matlab:help('bleLLAdvertisingChannelPDUConfig.PeripheralLatency')">PeripheralLatency</a>)*(<a
    %   href="matlab:help('bleLLAdvertisingChannelPDUConfig.ConnectionInterval')">ConnectionInterval</a>*1.25)*2)/10.
    %   This property indicates the timeout for a connection if no valid
    %   packet is received within this time. Each unit is taken as 10 ms so
    %   that the resultant connection timeout (ConnectionTimeout*10) is in
    %   the range of 100 ms to 32.0 s. The default value is 10.
    ConnectionTimeout = 10
    
    %UsedChannels List of used (good) data channels
    %   Specify the assigned data channel indices as an integer vector with
    %   element values in the range [0, 36]. The vector length must be
    %   greater than 1. At least two channels must be set as used (good)
    %   channels. This property indicates the set of good channels
    %   classified by the Central. The default value is a row vector
    %   containing all the channel indices [0:36].
    UsedChannels
    
    %HopIncrement Hop increment count
    %   Specify the hop increment as an integer in the range [5, 16]. This
    %   property indicates the hop increment count to be used for hopping
    %   between data channels. The default value is 5.
    HopIncrement = 5
    
    %SleepClockAccuracy Central sleep clock accuracy
    %   Specify the sleep clock accuracy as one of '251 to 500 ppm' | '151
    %   to 250 ppm' | '101 to 150 ppm' | '76 to 100 ppm' | '51 to 75 ppm' |
    %   '31 to 50 ppm' | '21 to 30 ppm' | '0 to 20 ppm'. This property
    %   indicates worst case Central sleep clock accuracy. The default
    %   value is '251 to 500 ppm'.
    SleepClockAccuracy
end

properties(Hidden)
    %HideDisplay Hide the properties of Link Layer configuration object
    %   This is a hidden property used by <a href="matlab:help('bleLLAdvertisingChannelPDUDecode')">bleLLAdvertisingChannelPDUDecode</a>
    %   function to disable the display of all the properties when Link
    %   Layer decoding is failed.
    HideDisplay (1, 1) logical = false
end

properties(Constant, Hidden)
    PDUType_Values = {...
        'Advertising indication'; ...
        'Scan request'; ...
        'Scan response'; ...
        'Advertising direct indication'; ...
        'Advertising non connectable indication'; ...
        'Connection indication'; ...
        'Advertising scannable indication'}
    
    ChannelSelection_Values = {...
        'Algorithm1'; ...
        'Algorithm2'}
    
    AddressType_Values = {...
        'Public'; ...
        'Random'}
    
    SleepClockAccuracy_Values = {...
        '251 to 500 ppm'; ...
        '151 to 250 ppm'; ...
        '101 to 150 ppm'; ...
        '76 to 100 ppm'; ...
        '51 to 75 ppm'; ...
        '31 to 50 ppm'; ...
        '21 to 30 ppm'; ...
        '0 to 20 ppm'}
end

methods(Hidden)
    function status = validatePeripheralLatency(obj)
        % Refer Bluetooth Core Specification v5.0 | Vol 6, Part B, Section
        % 4.5.1
        status = (obj.PeripheralLatency <= ...
            (((obj.ConnectionTimeout*10)/(obj.ConnectionInterval*1.25*2)) - 1));
    end
    
    function status = validateConnectionTimeout(obj)
        % Refer Bluetooth Core Specification v5.0 | Vol 6, Part B, Section
        % 4.5.2
        status = (obj.ConnectionTimeout > ...
            (((1+obj.PeripheralLatency)*(obj.ConnectionInterval*1.25)*2)/10));
    end
    
    function status = validateWindowSize(obj)
        % Refer Bluetooth Core Specification v5.0 | Vol 6, Part B, Section
        % 4.5.3
        if (obj.ConnectionInterval <= 8)
            status = (obj.WindowSize <= (obj.ConnectionInterval-1));
        else
            status = (obj.WindowSize <= 8);
        end
    end
    
    function status =  validateWindowOffset(obj)
        % Refer Bluetooth Core Specification v5.0 | Vol 6, Part B, Section
        % 4.5.3
        status = (obj.WindowOffset <= obj.ConnectionInterval);
    end
end

methods
    % Constructor
    function obj = bleLLAdvertisingChannelPDUConfig(varargin)
        % For code generation initialize variable sized properties in
        % constructor
        obj@comm.internal.ConfigBase('PDUType', 'Advertising indication', ...
            'AdvertisingData', '020106', 'ScanResponseData', '020106', ...
            'SleepClockAccuracy', '251 to 500 ppm', 'UsedChannels', (0:36), ...
            varargin{:})
    end
    
    % For auto completion
    function v = set(obj, prop)
        if any(strcmp(prop, {'AdvertiserAddressType', 'TargetAddressType', ...
                'ScannerAddressType', 'InitiatorAddressType'}))
            v = obj.('AddressType_Values');
        else
            v = obj.([prop, '_Values']);
        end
    end
    
    function obj = set.PDUType(obj, value)
        value = validatestring(value, ...
            obj.PDUType_Values, mfilename, 'PDUType');
        obj.PDUType = '';
        obj.PDUType = value;
    end
    
    function obj = set.ChannelSelection(obj, value)
        obj.ChannelSelection = validatestring(value, ...
            obj.ChannelSelection_Values, mfilename, 'ChannelSelection');
    end
    
    function obj = set.AdvertiserAddressType(obj, value)
        obj.AdvertiserAddressType = validatestring(value, ...
            obj.AddressType_Values, mfilename, 'AdvertiserAddressType');
    end
    
    function obj = set.TargetAddressType(obj, value)
        obj.TargetAddressType = validatestring(value, ...
            obj.AddressType_Values, mfilename, 'TargetAddressType');
    end
    
    function obj = set.ScannerAddressType(obj, value)
        obj.ScannerAddressType = validatestring(value, ...
            obj.AddressType_Values, mfilename, 'ScannerAddressType');
    end
    
    function obj = set.InitiatorAddressType(obj, value)
        obj.InitiatorAddressType = validatestring(value, ...
            obj.AddressType_Values, mfilename, 'InitiatorAddressType');
    end
    
    function obj = set.AdvertiserAddress(obj, value)
        ble.internal.validateHex(value, 12, 'AdvertiserAddress');
        obj.AdvertiserAddress = char(value);
    end
    
    function obj = set.TargetAddress(obj, value)
        ble.internal.validateHex(value, 12, 'TargetAddress');
        obj.TargetAddress = char(value);
    end
    
    function obj = set.ScannerAddress(obj, value)
        ble.internal.validateHex(value, 12, 'ScannerAddress');
        obj.ScannerAddress = char(value);
    end
    
    function obj = set.InitiatorAddress(obj, value)
        ble.internal.validateHex(value, 12, 'InitiatorAddress');
        obj.InitiatorAddress = char(value);
    end
    
    function obj = set.AdvertisingData(obj, value)
        if ~isempty(value)
            advData = ble.internal.convertPayloadToHexArray(value, ...
                'AdvertisingData');
        else
            advData = blanks(0);
        end
        validateattributes(numel(advData)/2, {'numeric'}, ...
            {'<=', 31}, mfilename, 'Advertising data size');
        obj.AdvertisingData = '';
        obj.AdvertisingData = advData;
    end
    
    function obj = set.ScanResponseData(obj, value)
        if ~isempty(value)
            scanRspData = ble.internal.convertPayloadToHexArray(value, ...
                'ScanResponseData');
        else
            scanRspData = blanks(0);
        end
        validateattributes(numel(scanRspData)/2, {'numeric'}, ...
            {'<=', 31}, mfilename, 'ScanResponseData');
        obj.ScanResponseData = '';
        obj.ScanResponseData = scanRspData;
    end
    
    function obj = set.AccessAddress(obj, value)
        ble.internal.validateHex(value, 8, 'AccessAddress');
        obj.AccessAddress = char(value);
    end
    
    function obj = set.CRCInitialization(obj, value)
        ble.internal.validateHex(value, 6, 'CRCInitialization');
        obj.CRCInitialization = char(value);
    end
    
    function obj = set.WindowSize(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', ...
            'integer', '>=', 1, '<=', 8}, mfilename, 'WindowSize');
        obj.WindowSize = value;
    end
    
    function obj = set.WindowOffset(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', ...
            'integer', '>=', 0, '<=', 3200}, mfilename, 'WindowOffset');
        obj.WindowOffset = value;
    end
    
    function obj = set.ConnectionInterval(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', ...
            'integer', '>=', 6, '<=', 3200}, mfilename, 'ConnectionInterval');
        obj.ConnectionInterval = value;
    end
    
    function obj = set.PeripheralLatency(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', ...
            'integer', '>=', 0, '<=', 499}, mfilename, 'PeripheralLatency');
        obj.PeripheralLatency = value;
    end
    
    function obj = set.ConnectionTimeout(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', ...
            'integer', '>=', 10, '<=', 3200}, mfilename, 'ConnectionTimeout');
        obj.ConnectionTimeout = value;
    end
    
    function obj = set.UsedChannels(obj, value)
        validateattributes(value, {'numeric'}, {'vector', ...
            'nonnegative', 'integer', '<=', 36}, mfilename, 'UsedChannels');
        value = unique(value);
        % At least two channels must be set as used (good) channels as
        % specified in Bluetooth Core Specification v5.0 - Vol 6, Part B,
        % Section 4.5.8.1.
        coder.internal.errorIf((numel(value) < 2), ...
            'bluetooth:bleLL:InvalidUsedChannels');
        obj.UsedChannels = value;
    end
    
    function obj = set.HopIncrement(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', ...
            'integer', '>=', 5, '<=', 16}, mfilename, 'HopIncrement');
        obj.HopIncrement = value;
    end
    
    function obj = set.SleepClockAccuracy(obj, value)
        value = validatestring(value, ...
            obj.SleepClockAccuracy_Values, mfilename, 'SleepClockAccuracy');
        obj.SleepClockAccuracy = '';
        obj.SleepClockAccuracy = value;
    end
end

methods(Access = protected)
    % Controls the conditional display of properties
    function flag = isInactiveProperty(obj, prop)
        % Initialize
        flag = true;
        
        % Disable display
        if obj.HideDisplay
            return;
        end
        
        % Applicable for all PDUs
        if any(strcmp(prop, {'PDUType', 'AdvertiserAddress', ...
                'AdvertiserAddressType'}))
            flag = false;
            return;
        end
        
        % Based on PDU type
        switch (obj.PDUType)
            case 'Advertising indication'
                flag = ~any(strcmp(prop, {'ChannelSelection', ...
                    'AdvertisingData'}));

            case {'Advertising scannable indication', ...
                    'Advertising non connectable indication'}
                flag = ~strcmp(prop, 'AdvertisingData');

            case 'Advertising direct indication'
                flag = ~any(strcmp(prop, {'ChannelSelection', ...
                    'TargetAddress', 'TargetAddressType'}));

            case 'Scan request'
                flag = ~any(strcmp(prop, {'ScannerAddress', ...
                    'ScannerAddressType'}));

            case 'Scan response'
                flag = ~strcmp(prop, 'ScanResponseData');

            case 'Connection indication'
                flag = ~any(strcmp(prop, ...
                    {'ChannelSelection', 'InitiatorAddress', ...
                    'InitiatorAddressType', 'AccessAddress', ...
                    'CRCInitialization', 'WindowSize', 'WindowOffset', ...
                    'ConnectionInterval', 'PeripheralLatency', ...
                    'ConnectionTimeout', 'UsedChannels', ...
                    'HopIncrement', 'SleepClockAccuracy'}));
        end
    end
end
end
