classdef helperBluetoothLogicalTransports < handle
%helperBluetoothLogicalTransports Manages logical transports (ACL and SCO)
%in Bluetooth
%   LT = helperBluetoothLogicalTransports creates an object for maintaining
%   the logical transports in Bluetooth. The object supports asynchronous
%   connection-oriented (ACL) and synchronous connection-oriented (SCO)
%   logical transports.
%
%   LT = helperBluetoothLogicalTransports(Name, Value) creates an object
%   for Bluetooth logical transports 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).
%
%   helperBluetoothLogicalTransports properties:
%
%   PrimaryAddress          - Primary logical transport address
%   SynchronousLink         - Flag to indicate the presence of SCO
%   PollInterval            - Maximum interval between two successive poll
%                             requests
%   SCOPacketType           - Type of the packet over SCO logical transport
%   FrequencyHop            - Bluetooth frequency hopping object to hop for
%                             each slot
%   ChannelClassification   - Bluetooth channel classification object to
%                             classify the channels

%   Copyright 2020 The MathWorks, Inc.

%#codegen

% Public properties
properties
    %PrimaryAddress Primary logical transport address
    %   Specify the primary logical transport address as a positive integer
    %   in the range [1, 7]. This property indicates the active destination
    %   Slave for a packet in a Master-to-Slave transmission slot. The
    %   default value is 1.
    PrimaryAddress = 1
    
    %SynchronousLink Flag to indicate the presence of SCO
    %   Specify this flag as a logical scalar value. To enable the SCO
    %   logical link between a Master and a Slave, set this property to
    %   true. The default value is false (disabled).
    SynchronousLink (1, 1) logical = false
    
    %PollInterval Maximum interval between two successive poll requests
    %   Specify the poll interval as a positive even integer in the range
    %   [6, 4096] slots. This property specifies the maximum interval
    %   between two successive poll requests on the ACL logical link. 1
    %   slot = 625 microseconds. The default value is 6.
    PollInterval = 6
    
    %SCOPacketType Type of the packet over SCO logical transport
    %   Specify the SCO packet type as 'HV1', 'HV2', or 'HV3'. This
    %   property indicates the type of the packet transmitted or received
    %   over the SCO logical transport. The maximum information bytes
    %   transmitted or received for 'HV1', 'HV2', and 'HV3' packet types
    %   are 10, 20, and 30 respectively. The default value is 'HV3'.
    SCOPacketType = 'HV3'
    
    %FrequencyHop Bluetooth frequency hopping object to hop for each slot
    %   Specify this property as an object of type <a
    %   href="matlab:help('bluetoothFrequencyHop')">bluetoothFrequencyHop</a>.
    %   The object uses this property to hop between the frequencies
    %   for each slot. The default value is an object of type
    %   'bluetoothFrequencyHop' with all properties set to their default
    %   values.
    FrequencyHop
    
    %ChannelClassification Bluetooth channel classification object to
    %classify the channels
    %   Specify this property as an object of type <a
    %   href="matlab:help('helperBluetoothChannelClassification')">helperBluetoothChannelClassification</a>.
    %   This property classifies the Bluetooth channels into good or bad
    %   channels for each <a
    %   href="matlab:help('helperBluetoothChannelClassification.ClassificationInterval')">ClassificationInterval</a>
    %   number of slots. The default value is an object of type
    %   'helperBluetoothChannelClassification' with all properties set to
    %   their default values.
    ChannelClassification
end

% Constant, Hidden properties
properties (Constant, Hidden)
    % Packet types transmitted over SCO logical transport
    SCOPacketTypeValues = {'HV1', 'HV2', 'HV3'}
end

% Hidden properties
properties (Hidden)
    %SCOInterval Interval between two successive SCO packets
    %   Specify the SCO interval as 2, 4, or 6 slots. It specifies the
    %   interval between two successive SCO packets on SCO logical link. 1
    %   slot = 625 microseconds. The default value is 6.
    SCOInterval = 6
    
    %ACLQueue Queue for ACL data
    ACLQueue
    
    %SCOQueue Queue for SCO data
    SCOQueue
    
    %ACLSEQN 1-bit sequence number for ACL logical transport
    %   Specify the ACL SEQN as 0 or 1. This property provides a sequential
    %   numbering scheme to order the data packet stream. This will be
    %   toggled for every new data packet. The default value is 1.
    ACLSEQN = 1
    
    %RecvACLSEQN SEQN field in the received ACL packet
    RecvACLSEQN = -1
    
    %RecvACLStatus Specify whether the received packet on ACL link is
    %received valid or not (without any CRC or HEC errors)
    % 0 - Received ACL packet is not valid
    % 1 - Received ACL packet is valid
    RecvACLStatus = 1
    
    %RecvSCOStatus Specify whether the received packet on SCO link is
    %received valid or not (without any CRC or HEC errors)
    % 0 - Received SCO packet is not valid
    % 1 - Received SCO packet is valid
    RecvSCOStatus = 1
    
    %ChannelsClassified Flag to check whether the channels are classified
    %or not
    ChannelsClassified = false
    
    %ClassificationSent Flat to specify whether the channel classification
    %is sent or not
    ClassificationSent = false
    
    %UsedChannels List of used channels derived after channel
    %classification
    UsedChannels = ones(1, 79)

    %AFHInstant Instant of the future clock after which the channel
    %classification need to be used
    AFHInstant = 0
    
    %ClassificationTimer Timer for the classification interval
    ClassificationTimer = 0
    
    %RespFlag Flag to identify whether need to send response packet or not
    RespFlag = false
end

% Public methods
methods
    % Constructor
    function obj = helperBluetoothLogicalTransports(varargin)
        % Initialize the frequency hop object
        obj.FrequencyHop = bluetoothFrequencyHop;
        % Initialize the channel classification object
        obj.ChannelClassification = helperBluetoothChannelClassification;
        % Maximum number of packets that can be stored on each logical
        % transport ACL and SCO queues
        maxQueueSize = 5;
        maxACLPayloadSize = 3200; % Max ACL payload size is 3200 bits (400 bytes)
        maxSCOPayloadSize = 240; % Max SCO payload size is 240 bits (30 bytes)
        obj.ACLQueue = helperBluetoothQueue(maxQueueSize, maxACLPayloadSize);
        obj.SCOQueue = helperBluetoothQueue(maxQueueSize, maxSCOPayloadSize);
        
        % Name-value pairs
        for idx = 1:2:nargin
            obj.(varargin{idx}) = varargin{idx+1};
        end
    end
    
    % Auto-completion
    function v = set(obj, prop)
        v = obj.([prop, 'Values']);
    end
    
    % Validate primary address
    function set.PrimaryAddress(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'positive', ...
            'integer', '<=', 7, '>=', 1}, mfilename, 'PrimaryAddress');
        obj.PrimaryAddress = value;
    end
    
    % Validate poll interval
    function set.PollInterval(obj, value)
        validateattributes(value, {'numeric'}, {'scalar', 'nonnegative', ...
            'integer', '>=', 6, 'even', '<=', 4096}, mfilename, ...
            'PollInterval');
        obj.PollInterval = value;
    end
    
    % Validate synchronous link type
    function set.SCOPacketType(obj, value)
        obj.SCOPacketType = validatestring(value, ...
            obj.SCOPacketTypeValues, mfilename, 'SCOPacketType');
        % Update the SCO interval
        switch value
            % HV1
            case 'HV1'
                obj.SCOInterval = 2; %#ok<*MCSUP>
            % HV2
            case 'HV2'
                obj.SCOInterval = 4;
            % HV3
            case 'HV3'
                obj.SCOInterval = 6;
        end 
    end
        
    % Validate frequency hop object
    function set.FrequencyHop(obj, value)
        validateattributes(value, {'bluetoothFrequencyHop'}, {'scalar'}, ...
            mfilename, 'FrequencyHop');
        obj.FrequencyHop = value;
    end
    
    % Validate channel classification object
    function set.ChannelClassification(obj, value)
        validateattributes(value, {'helperBluetoothChannelClassification'}, ...
            {'scalar'}, mfilename, 'ChannelClassification');
        obj.ChannelClassification = value;
    end
    
    function lmpPDU = generateClassificationPDU(obj)
    %generateClassificationPDU Generates LMP set AFH PDU to send the
    %updated channel map to the Slave
        
        % Create LMP (link manager protocol) PDU configuration object
        lmpConfig = helperBluetoothLMPPDUConfig;
        % Form channel classification PDU
        lmpConfig.PDUType = 'LMP set AFH';
        % Transaction is initiated by the Master
        lmpConfig.TransactionID = 0;
        % The AFH instant is chosen by the Master and shall be an
        % even value at least 6*Tpoll or 96 slots (whichever is
        % greater) in the future.
        % Refer Bluetooth core specification v5.1, Vol 2, PART C,
        % Section 4.1.4.
        lmpConfig.AFHInstant = max(6*obj.PollInterval, 96)*2;
        lmpConfig.AFHMode = true;
        lmpConfig.UsedChannels = find(obj.ChannelClassification.ChannelMap)-1;
        % Store the used channels derived after channel
        % classification
        obj.UsedChannels = lmpConfig.UsedChannels;
        obj.AFHInstant = lmpConfig.AFHInstant;
        
        % Generate the LMP PDU
        lmpPDU = helperBluetoothLMPPDU(lmpConfig);
    end
end
end

% LocalWords:  AFH PDU LMP ACL SCO HV SEQN CRC HEC ACK
