classdef bleATTPDUConfig < comm.internal.ConfigBase
%bleATTPDUConfig Bluetooth LE ATT PDU configuration parameters
%   CFGATT = bleATTPDUConfig creates a default Bluetooth(R) low energy (LE)
%   attribute protocol data unit (ATT PDU) configuration object.
%
%   CFGATT = bleATTPDUConfig(Name, Value) creates a Bluetooth LE ATT PDU
%   configuration object, CFGATT, 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).
%
%   bleATTPDUConfig properties:
%
%   Opcode                - ATT PDU operation code
%   RequestedOpcode       - Opcode of a request PDU that caused an error
%   Format                - Format of an information data field
%   AttributeHandle       - Handle value of an attribute
%   ErrorMessage          - Description of an error
%   MaxTransmissionUnit   - Maximum size of an ATT PDU
%   StartHandle           - Starting handle in a handle range
%   EndHandle             - Ending handle in a handle range
%   AttributeType         - Type of an attribute
%   AttributeValue        - Value of an attribute
%   Offset                - Offset of the next octet to be read
%   ExecuteWrite          - Flag field in 'Execute write request' command
%
%   % Example 1:
%   % Create a bleATTPDUConfig object for an ATT PDU of type 'Read by type
%   % request'.
%
%   cfgATT = bleATTPDUConfig;
%   cfgATT.Opcode           = 'Read by type request';
%   cfgATT.AttributeType    = '2800';
%   cfgATT.StartHandle      = '0001';
%   cfgATT.EndHandle        = 'FFFF'
%
%   % Example 2:
%   % Create a bleATTPDUConfig object for an ATT PDU of type 'Error
%   % response' using Name-Value pairs.
%
%   cfgATT = bleATTPDUConfig('Opcode', 'Error response', ...
%                       'RequestedOpcode', 'Read by type request', ...
%                       'AttributeHandle', '0001', ...
%                       'ErrorMessage', 'Invalid handle')
%
%   % Example 3:
%   % Bluetooth LE ATT PDUs end-to-end workflow.
%
%   % Tx side
%   % Create a bleATTPDUConfig object for an ATT PDU of type 'Read by type
%   % request'.
%   cfgTx = bleATTPDUConfig;
%   cfgTx.Opcode         = 'Read by type request';
%   cfgTx.AttributeType  = '2800';
%   cfgTx.StartHandle    = '0001';
%   cfgTx.EndHandle      = 'FFFF'
%
%   % Generate an ATT PDU using configuration object 'cfgTx'.
%   attPDU = bleATTPDU(cfgTx);
%
%   % Rx side
%   % Decode the received ATT PDU.
%   [status, cfgRx] = bleATTPDUDecode(attPDU);
%   if strcmp(status, 'Success') % Decoding is successful
%       cfgRx
%   else
%       fprintf('ATT PDU decoding failed due to ::');
%       status
%   end
%
%   See also bleATTPDU, bleATTPDUDecode.

%   Copyright 2018-2022 The MathWorks, Inc.

%#codegen

properties
    %Opcode ATT PDU operation code
    %   Specify the operation code as one of 'Error response' | 'MTU
    %   request' | 'MTU response' | 'Information request' | 'Find by type
    %   value request' | 'Read by type request' | 'Read request' | 'Read
    %   response' | 'Read blob request' | 'Read blob response' | 'Read by
    %   group type request' | 'Write request' | 'Write response' | 'Write
    %   command' | 'Prepare write request' | 'Prepare write response' |
    %   'Execute write request' | 'Execute write response' | 'Handle value
    %   notification' | 'Handle value indication' | 'Handle value
    %   confirmation' | 'Information response' | 'Find by type value
    %   response' | 'Read by type response' | 'Read by group type
    %   response'. It describes an attribute protocol operation to be
    %   performed. The default value is 'Read request'.
    Opcode

    %RequestedOpcode Opcode of a request PDU that caused an error
    %   Specify opcode of the request PDU that caused an error as one of
    %   'MTU request' | 'Information request' | 'Find by type value
    %   request' | 'Read by type request' | 'Read request' | 'Read blob
    %   request' | 'Read by group type request' | 'Write request' |
    %   'Prepare write request' | 'Execute write request'. It indicates a
    %   request PDU from a peer device that caused an error. The default
    %   value is 'Read request'.
    RequestedOpcode

    %Format Format of an information data field
    %   Specify the format as one of '16 bit' | '128 bit'. It describes the
    %   format of information data element in 'Find Information Response'
    %   PDU. The default value is '16 bit'.
    Format

    %AttributeHandle Handle value of an attribute
    %   Specify the attribute handle as a 4-element character vector or
    %   string scalar denoting a 2-octet hexadecimal value in the range
    %   [0x0001, 0xFFFF]. Attribute handle is a unique identifier of an
    %   attribute. Attribute handles are dynamically assigned by the
    %   server. The default value is '0001'.
    AttributeHandle = '0001'

    %ErrorMessage Description of an error
    %   Specify the error message as one of 'Invalid handle' | 'Read not
    %   permitted' | 'Write not permitted' | 'Invalid PDU' | 'Insufficient
    %   authentication' | 'Request not supported' | 'Invalid offset' |
    %   'Insufficient authorization' | 'Prepare queue full' | 'Attribute
    %   not found' | 'Attribute not long' | 'Insufficient encryption key
    %   size' | 'Invalid attribute value length' | 'Unlikely error' |
    %   'Insufficient encryption' | 'Unsupported group type' |
    %   'Insufficient resources'. It indicates the reason for an error
    %   corresponding to the request PDU from a peer device. The default
    %   value is 'Invalid handle'.
    ErrorMessage

    %MaxTransmissionUnit Maximum size of an ATT PDU
    %   Specify the MTU as an integer in the range [23, 65535]. This
    %   property shall be set to the maximum size of the attribute protocol
    %   PDU that can send or receive. The default value is 23.
    MaxTransmissionUnit = 23

    %StartHandle Starting handle of a handle range
    %   Specify the starting handle as a 4-element character vector or
    %   string scalar denoting a 2-octet hexadecimal value in the range
    %   [0x0001, 0xFFFF] and it should not be greater than the <a
    %   href="matlab:help('bleATTPDUConfig.EndHandle')">EndHandle</a>. It
    %   holds the handle value of a service declaration or a characteristic
    %   declaration, or the starting handle of a handle range. The default
    %   value is '0001'.
    StartHandle = '0001'

    %EndHandle Ending handle of a handle range
    %   Specify the ending handle as a 4-element character vector or string
    %   scalar denoting a 2-octet hexadecimal value in the range
    %   [0x0001, 0xFFFF] and it should not be less than the <a
    %   href="matlab:help('bleATTPDUConfig.StartHandle')">StartHandle</a>.
    %   It holds the end handle value of a service declaration or a
    %   characteristic declaration, or the ending handle of a handle range.
    %   The default value is 'FFFF'.
    EndHandle = 'FFFF'

    %AttributeType Type of the attribute
    %   Specify the attribute type as a 4-element/32-element character
    %   vector or string scalar denoting a 2-octet/16-octet hexadecimal
    %   value. It indicates what the attribute represents. The default
    %   value is '2800' (Primary service).
    AttributeType = '2800'

    %AttributeValue Value of an attribute
    %   Specify the attribute value as a character vector or string scalar
    %   or nX2 character array of length up to 131068 (65534*2). It can
    %   also specified as a numeric vector (each element is in the range
    %   [0, 255]) of length up to 65534. It is in LSB first format. It
    %   indicates the value of an attribute that is to be stored in or read
    %   from the attribute database. The default value is '' (empty).
    AttributeValue

    %Offset Offset of the next octet to be read
    %   Specify the offset as an integer in the range [0, 65535]. It is
    %   used in 'Read blob request', 'Prepare write request' and 'Prepare
    %   write response' PDUs to identify an attribute value offset in
    %   attribute database. The default value is 0.
    Offset = 0

    %ExecuteWrite Flag field in 'Execute write request' command
    %   Specify the execute write flag as one of 'Cancel all prepared
    %   writes' | 'Write all pending requests'. Used to determine the
    %   action (discard or write) to be performed when execute write
    %   command is issued. The default value is 'Cancel all prepared
    %   writes'.
    ExecuteWrite
end

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

properties(Constant, Hidden)
    Opcode_Values = {...
        'Error response'; ...
        'MTU request'; ...
        'MTU response'; ...
        'Information request'; ...
        'Find by type value request'; ...
        'Read by type request'; ...
        'Read request'; ...
        'Read response'; ...
        'Read blob request'; ...
        'Read blob response'; ...
        'Read by group type request'; ...
        'Write request'; ...
        'Write response'; ...
        'Write command'; ...
        'Prepare write request'; ...
        'Prepare write response'; ...
        'Execute write request'; ...
        'Execute write response'; ...
        'Handle value notification'; ...
        'Handle value indication'; ...
        'Handle value confirmation'; ...
        'Information response'; ...
        'Find by type value response'; ...
        'Read by type response'; ...
        'Read by group type response'}

    RequestedOpcode_Values = {...
        'MTU request';  ...
        'Information request'; ...
        'Find by type value request'; ...
        'Read by type request'; ...
        'Read request'; ...
        'Read blob request'; ...
        'Read by group type request'; ...
        'Write request'; ...
        'Prepare write request'; ...
        'Execute write request'}

    ErrorMessage_Values = {...
        'Invalid handle'; ...
        'Read not permitted'; ...
        'Write not permitted'; ...
        'Invalid PDU'; ...
        'Insufficient authentication'; ...
        'Request not supported'; ...
        'Invalid offset'; ...
        'Insufficient authorization'; ...
        'Prepare queue full'; ...
        'Attribute not found'; ...
        'Attribute not long'; ...
        'Insufficient encryption key size'; ...
        'Invalid attribute value length'; ...
        'Unlikely error'; ...
        'Insufficient encryption'; ...
        'Unsupported group type'; ...
        'Insufficient resources'}

    ExecuteWrite_Values = {...
        'Cancel all prepared writes'; ...
        'Write all pending requests'}

    Format_Values = {'16 bit'; '128 bit'}

    % Refer Bluetooth core specification, v5.0, Vol 3, PART B, Section
    % 2.5.1
    BluetoothBaseUUID = '0000000000001000800000805F9B34FB'
end

methods
    function obj = bleATTPDUConfig(varargin)
        % For codegen initialize variable sized properties in constructor
        obj@comm.internal.ConfigBase('Opcode', 'Read request', ...
            'RequestedOpcode', 'Read request', ...
            'Format', '16 bit', ...
            'ErrorMessage', 'Invalid handle', ...
            'AttributeValue', blanks(0), ...
            'ExecuteWrite', 'Cancel all prepared writes', 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.AttributeHandle(obj, value)
        ble.internal.validateHex(value, 4, 'AttributeHandle');
        obj.AttributeHandle = char(value);
    end

    function obj = set.AttributeType(obj, value)
        validateattributes(value, {'char', 'string'}, {}, mfilename, ...
            'AttributeType');
        if ischar(value)
            attributeLength = numel(value);
        else
            attributeLength = strlength(value);
        end
        coder.internal.errorIf(((attributeLength ~= 4) && ...
            (attributeLength ~= 32)), 'bluetooth:bleATT:InvalidAttributeType')
        ble.internal.validateHex(value, attributeLength, 'AttributeType');
        obj.AttributeType = char(value);
    end

    function obj = set.RequestedOpcode(obj, value)
        value = validatestring(value, ...
            obj.RequestedOpcode_Values, mfilename, 'RequestedOpcode');
        obj.RequestedOpcode = '';
        obj.RequestedOpcode = value;
    end

    function obj = set.Format(obj, value)
        value = validatestring(value, obj.Format_Values, mfilename, ...
            'Format');
        obj.Format = '';
        obj.Format = value;
    end

    function obj = set.ErrorMessage(obj, value)
        value = validatestring(value, obj.ErrorMessage_Values, ...
            mfilename, 'ErrorMessage');
        obj.ErrorMessage = '';
        obj.ErrorMessage = value;
    end

    function obj = set.MaxTransmissionUnit(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'integer', ...
            '>=', 23, '<=', 65535}, mfilename, 'MaxTransmissionUnit');
        obj.MaxTransmissionUnit = value;
    end

    function obj = set.StartHandle(obj, value)
        ble.internal.validateHex(value, 4, 'StartHandle');
        obj.StartHandle = char(value);
    end

    function obj = set.EndHandle(obj, value)
        ble.internal.validateHex(value, 4, 'EndHandle');
        obj.EndHandle = char(value);
    end

    function obj = set.AttributeValue(obj, value)
        if ~isempty(value)
            attributeValue = ble.internal.convertPayloadToHexArray(value, ...
                'AttributeValue');
        else
            attributeValue = value;
        end
        validateattributes(numel(attributeValue)/2, {'numeric'}, {'scalar', ...
            'integer', '<=', 131068}, mfilename, 'AttributeValueSize');
        obj.AttributeValue = '';
        obj.AttributeValue = attributeValue;
    end

    function obj = set.Offset(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'integer', ...
            '>=', 0, '<=', 65535}, mfilename, 'Offset');
        obj.Offset = value;
    end

    function obj = set.ExecuteWrite(obj, value)
        value = validatestring(value, ...
            obj.ExecuteWrite_Values, mfilename, 'ExecuteWrite');
        obj.ExecuteWrite = '';
        obj.ExecuteWrite = value;
    end
end

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

        % Disable display of all the properties
        if obj.HideDisplay
            return;
        end

        switch prop
            % Opcode is applicable for all PDU types
            case 'Opcode'
                flag = false;
                
            % AttributeHandle is applicable for 'Error response', 'Read
            % request', 'Read blob request', 'Write request', 'Write
            % Response', 'Write command', 'Prepare write request', 'Prepare
            % write response', 'Handle value notification', 'Handle value
            % indication', 'Read by type response' 'Information response'
            % PDU types
            case 'AttributeHandle'
                if any(strcmp(obj.Opcode, {'Error response', ...
                    'Read request', 'Read blob request', ...
                    'Write request', ...
                    'Write command', 'Prepare write request', ...
                    'Prepare write response', ...
                    'Handle value notification', ...
                    'Handle value indication', 'Read by type response',...
                    'Information response'}))
                    flag = false;
                end
                
            % RequestedOpcode and ErrorMessage are applicable for 'Error
            % response' PDU type
            case {'RequestedOpcode', 'ErrorMessage'}
                if strcmp(obj.Opcode, 'Error response')
                    flag = false;
                end
                
            % MaxTransmissionUnit is applicable for 'MTU request', 'MTU
            % response' PDU types
            case 'MaxTransmissionUnit'
                if any(strcmp(obj.Opcode, {'MTU request', ...
                        'MTU response'}))
                    flag = false;
                end
                
            % StartHandle and EndHandle are applicable for 'Information
            % request', 'Find by type value request', 'Read by type
            % request', 'Read by group type request', 'Read by group type
            % response', 'Find by type value response' PDU types
            case {'StartHandle', 'EndHandle'}
                if any(strcmp(obj.Opcode, {'Information request', ...
                        'Find by type value request', ...
                        'Read by type request', 'Read by group type request', ...
                        'Read by group type response', ...
                        'Find by type value response'}))
                    flag = false;
                end
                
            % AttributeType is applicable for 'Find by type value request',
            % 'Read by type request', 'Read by group type request',
            % 'Information response' PDU types
            case 'AttributeType'
                if any(strcmp(obj.Opcode, {'Find by type value request', ...
                        'Read by type request', 'Read by group type request', ...
                        'Information response'}))
                    flag = false;
                end
               
            % AttributeValue is applicable for 'Find by type value
            % request', 'Read response', 'Read blob response', 'Write
            % request', 'Write command', 'Prepare write request', 'Prepare
            % write response', 'Handle value notification', 'Handle value
            % indication', 'Read by type response', 'Read by group type
            % response' PDU types
            case 'AttributeValue'
                if any(strcmp(obj.Opcode, {'Find by type value request', ...
                        'Read response', 'Read blob response', ...
                        'Write request', 'Write command', ...
                        'Prepare write request', 'Prepare write response', ...
                        'Handle value notification', ...
                        'Handle value indication', 'Read by type response', ...
                        'Read by group type response'}))
                    flag = false;
                end
                
            % Offset is applicable for 'Read blob request', 'Prepare write
            % request', 'Prepare write response' PDU types
            case 'Offset'
                if any(strcmp(obj.Opcode, {'Read blob request', ...
                        'Prepare write request', 'Prepare write response'}))
                    flag = false;
                end
                
            % ExecuteWrite is applicable for 'Execute write request' PDU
            % type
            case 'ExecuteWrite'
                if strcmp(obj.Opcode, 'Execute write request')
                    flag = false;
                end
        
            % Format is applicable for 'Information response' PDU type
            case 'Format'
                if strcmp(obj.Opcode, 'Information response')
                    flag = false;
                end
        end
    end
end
end
