classdef bleLLControlPDUConfig < comm.internal.ConfigBase
%bleLLControlPDUConfig Bluetooth LE LL control PDU payload configuration
%parameters
%   CFGLLCTRL = bleLLControlPDUConfig creates a default Bluetooth(R) low
%   energy (LE) link layer control protocol data unit (PDU) payload
%   configuration object.
%
%   CFGLLCTRL = bleLLControlPDUConfig(Name, Value) creates a Bluetooth LE
%   Link Layer control PDU payload configuration object, CFGLLCTRL, 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).
%
%   bleLLControlPDUConfig properties:
%
%   Opcode             - Type of control PDU
%   WindowSize         - Transmit window size
%   WindowOffset       - Transmit window offset
%   ConnectionInterval - Connection interval
%   PeripheralLatency  - Peripheral latency
%   ConnectionTimeout  - Connection supervision timeout
%   Instant            - Connection event instant
%   UsedChannels       - List of used (good) data channels
%   ErrorCode          - Connection termination error code
%   UnknownOpcode      - Unrecognized or unsupported opcode
%   VersionNumber      - Version number of Bluetooth specification
%   CompanyIdentifier  - Manufacturer ID of Bluetooth controller
%   SubVersionNumber   - Sub-version number of Bluetooth controller  
%
%   % Example 1:
%   % Create a bleLLControlPDUConfig object for a control PDU, then assign
%   % the Opcode to 'Connection update indication' with connection interval
%   % set to 64 (80 ms, each unit taken as 1.25 ms).
%
%   cfgLLCtrl = bleLLControlPDUConfig;
%   cfgLLCtrl.Opcode             = 'Connection update indication';
%   cfgLLCtrl.ConnectionInterval = 64
%
%   % Example 2:
%   % Create a bleLLControlPDUConfig object for a control PDU of type
%   % 'Terminate indication' with error code set as 'Connection Timeout'.
%
%   cfgLLCtrl = bleLLControlPDUConfig('Opcode', 'Terminate indication', ...
%                                    'ErrorCode', 'Connection Timeout')
%
%   % Example 3:
%   % Generate a control PDU of type 'Channel map indication'
%   % with used channels set as '[0 3 12 16 18 24]'.
% 
%   cfgLLCtrl = bleLLControlPDUConfig('Opcode', 'Channel map indication');
%   cfgLLCtrl.UsedChannels = [0 3 12 16 18 24]
%   cfgLLData = bleLLDataChannelPDUConfig('LLID', 'Control');
%   cfgLLData.ControlConfig = cfgLLCtrl
%   pdu = bleLLDataChannelPDU(cfgLLData);
%
%   % Example 4:
%   % Link Layer data channel PDUs end-to-end workflow.
%
%   % Tx side
%   % Create a bleLLControlPDUConfig object for a control PDU of type
%   % 'Connection update indication'.
%   cfgLLCtrl = bleLLControlPDUConfig;
%   cfgLLCtrl.Opcode = 'Connection update indication'
%   cfgTx = bleLLDataChannelPDUConfig('LLID', 'Control', ...
%                                     'ControlConfig', cfgLLCtrl);
%   cfgTx.CRCInitialization = 'E23456';
%
%   %  Generate a control PDU using 'cfgTx'.
%   pdu = bleLLDataChannelPDU(cfgTx);
%
%   % Rx side
%   crcInit = 'E23456'; % Received during association
%   % Decode a Link Layer data channel PDU.
%   [status, cfgRx, llPayload] = bleLLDataChannelPDUDecode(pdu, crcInit);
%   if strcmp(status, 'Success') % Decoding is successful
%       cfgRx.ControlConfig % Control PDU configuration
%   else
%       fprintf('Link Layer decoding status ::');
%       status
%   end
%
%   See also bleLLDataChannelPDUConfig, bleLLDataChannelPDU
%   bleLLDataChannelPDUDecode.

%   Copyright 2018-2022 The MathWorks, Inc.

%#codegen

properties
    %Opcode Type of control PDU
    %   Specify the opcode as one of 'Connection update indication' |
    %   'Channel map indication' | 'Terminate indication' | 'Unknown
    %   response' | 'Version indication' | 'Reject indication'. This
    %   property indicates the type of control PDU. The default value is
    %   'Connection update indication'.
    Opcode
    
    %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('bleLLControlPDUConfig.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('bleLLControlPDUConfig.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('bleLLControlPDUConfig.ConnectionTimeout')">ConnectionTimeout</a>*10)/((<a
    %   href="matlab:help('bleLLControlPDUConfig.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('bleLLControlPDUConfig.PeripheralLatency')">PeripheralLatency</a>)*(<a
    %   href="matlab:help('bleLLControlPDUConfig.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
    
    %Instant Connection event instant
    %   Specify instant as an integer in the range [0, 65535]. This
    %   property indicates the event count at which certain action needs to
    %   take place (e.g. using updated connection parameters). The default
    %   value is 0.
    Instant = 0
    
    %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
    
    %ErrorCode Connection termination error code
    %   Specify the connection termination error code as one of 'Success' |
    %   'Unknown connection identifier' | 'Hardware failure' | 'Memory
    %   capacity exceeded' | 'Connection timeout' | 'Connection limit
    %   exceeded' | 'Connection already exists' | 'Command disallowed' |
    %   'Connection accept timeout exceeded' | 'Connection rejected due to
    %   limited resources' | 'Invalid LL parameters' | 'Connection rejected
    %   due to unacceptable BD_ADDR' | 'Unspecified error' | 'Unsupported
    %   LL parameter value' | 'Role change not allowed' | 'LL response
    %   timeout' | 'LL procedure collision' | 'Instant passed' | 'Channel
    %   classification not supported' | 'Extended inquiry response too
    %   large' | 'Connection rejected due to no suitable channel found' |
    %   'Advertising timeout' | 'Controller busy' | 'Unacceptable
    %   connection parameters' | 'Connection failed to be established' |
    %   'Unknown advertising identifier' | 'Limit reached' | 'Operation
    %   cancelled by host'. This property indicates the error description
    %   (e.g. 'Unknown connection identifier', 'Connection timeout') set to
    %   inform the remote device why the connection is about to be
    %   terminated. The default value is 'Success'.
    ErrorCode

    %UnknownOpcode Unrecognized or unsupported opcode
    %   Specify the unknown opcode as a 2-element character vector or
    %   string scalar denoting a 1-octet hexadecimal value. This property
    %   indicates the type of control PDU that is not recognized /
    %   supported. The default value is '00'.
    UnknownOpcode = '00'
    
    %VersionNumber Version number of Bluetooth specification
    %   Specify the version number as one of '4.0' | '4.1' | '4.2' | '5.0'.
    %   This property indicates the version of the Bluetooth core
    %   specification. The default value is '5.0'.
    VersionNumber = '5.0'
    
    %CompanyIdentifier Manufacturer ID of Bluetooth controller
    %   Specify the company identifier as a 4-element character vector or
    %   string scalar denoting a 2-octet hexadecimal value. This property
    %   indicates the unique identifier assigned to the company by
    %   Bluetooth SIG. The default value is 'FFFF' (used in the internal
    %   and interoperability tests).
    CompanyIdentifier = 'FFFF'
    
    %SubVersionNumber Sub-version number of Bluetooth controller
    %   Specify the sub-version number as a 4-element character vector or
    %   string scalar denoting a 2-octet hexadecimal value. This property
    %   indicates the unique value for each implementation or revision of
    %   an implementation of the Bluetooth controller. The default value is
    %   '0000'.
    SubVersionNumber = '0000'
end
  
properties(Constant, Hidden)
    Opcode_Values = {...
        'Connection update indication'; ...
        'Channel map indication'; ...
        'Terminate indication'; ...
        'Unknown response'; ...
        'Version indication'; ...
        'Reject indication'}
    
    VersionNumber_Values = {...
        '4.0'; ...
        '4.1'; ...
        '4.2'; ...
        '5.0'}
    
    ErrorCode_Values = {...
        'Success'; ...
        'Unknown connection identifier'; ...
        'Hardware failure'; ...
        'Memory capacity exceeded'; ...
        'Connection timeout'; ...
        'Connection limit exceeded'; ...
        'Connection already exists'; ...
        'Command disallowed'; ...
        'Connection accept timeout exceeded'; ...
        'Connection rejected due to limited resources'; ...
        'Invalid LL parameters'; ...
        'Connection rejected due to unacceptable BD_ADDR'; ...
        'Unspecified error'; ...
        'Unsupported LL parameter value'; ...
        'Role change not allowed'; ...
        'LL response timeout'; ...
        'LL procedure collision'; ...
        'Instant passed'; ...
        'Channel classification not supported'; ...
        'Extended inquiry response too large'; ...
        'Connection rejected due to no suitable channel found'; ...
        'Advertising timeout'; ...
        'Controller busy'; ...
        'Unacceptable connection parameters'; ...
        'Connection failed to be established'; ...
        'Unknown advertising identifier'; ...
        'Limit reached'; ...
        'Operation cancelled by host'}
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 = bleLLControlPDUConfig(varargin)
        % For code generation initialize variable sized properties in
        % constructor
        obj@comm.internal.ConfigBase('Opcode', ...
            'Connection update indication', 'ErrorCode', 'Success', ...
            'UsedChannels', (0:36), varargin{:});
    end
    
    function obj = set.Opcode(obj, value)
        value = validatestring(value, ...
            obj.Opcode_Values, mfilename, 'Opcode');
        obj.Opcode = '';
        obj.Opcode = 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.Instant(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', ...
            'integer', '>=', 0, '<=', 65535}, mfilename, 'Instant');
        obj.Instant = 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.ErrorCode(obj, value)
        value = validatestring(value, ...
            obj.ErrorCode_Values, mfilename, 'ErrorCode');
        obj.ErrorCode = '';
        obj.ErrorCode = value;
    end
    
    function obj = set.UnknownOpcode(obj, value)
        ble.internal.validateHex(value, 2, 'UnknownOpcode');
        obj.UnknownOpcode = char(value);
    end
    
    function obj = set.VersionNumber(obj, value)
        obj.VersionNumber = validatestring(value, ...
            obj.VersionNumber_Values, mfilename, 'VersionNumber');
    end
    
    function obj = set.CompanyIdentifier(obj, value)
        ble.internal.validateHex(value, 4, 'CompanyIdentifier');
        obj.CompanyIdentifier = char(value);
    end
    
    function obj = set.SubVersionNumber(obj, value)
        ble.internal.validateHex(value, 4, 'SubVersionNumber');
        obj.SubVersionNumber = char(value);
    end
end
  
methods(Access = protected)
    % Controls the conditional display of properties
    function flag = isInactiveProperty(obj, prop)
        % Initialize
        flag = true;
        
        % Applicable for all PDUs
        if strcmp(prop, 'Opcode')
            flag = false;
            return;
        end
        
        % Based on Opcode
        switch (obj.Opcode)
            case 'Connection update indication'
                flag = ~any(strcmp(prop, {'WindowSize', 'WindowOffset', ...
                    'ConnectionInterval', 'PeripheralLatency', 'ConnectionTimeout', ...
                    'Instant'}));

            case 'Channel map indication'
                flag = ~any(strcmp(prop, {'UsedChannels', 'Instant'}));

            case {'Terminate indication', 'Reject indication'}
                flag = ~strcmp(prop, 'ErrorCode');

            case 'Unknown response'
                flag = ~strcmp(prop, 'UnknownOpcode');

            case 'Version indication'
                flag = ~any(strcmp(prop, {'VersionNumber', ...
                    'CompanyIdentifier', 'SubVersionNumber'}));
        end
    end
end
end
