function [filtParams,configParams] = helperBLEModulationTestConfig(testID,sps)
%helperBLEModulationTestConfig returns BLE test parameters for each BLE
%transmitter test corresponding to modulation characteristics, carrier
%frequency offset and drift.
%   [FILTPARAMS,CONFIGPARAMS] = helperBLEModulationTestConfig(TESTID,SPS)
%   returns BLE transmitter test parameters, CONFIGPARAMS and designed
%   channel filter, FILTPARAMS.
%   
%   TESTID is a character vector or string specifying the transmitter test
%   ID. It must be one of the following:
%   {'RF-PHY/TRM/BV-09-C','RF-PHY/TRM/BV-11-C',
%    'RF-PHY/TRM/BV-13-C','RF-PHY/TRM/BV-06-C',
%    'RF-PHY/TRM/BV-12-C','RF-PHY/TRM/BV-14-C'}.
%   
%   SPS represents the number of samples per symbol.
%   
%   FILTPARAMS, a class with channel filter specifications designed as per
%   the test parameters. It contains the following properties:
%   COEFFICIENTS      - Filter coefficients
%   FREQUENCYRESPONSE - Frequency response of the filter
%   IMPULSERESPONSE   - Impulse response of the filter
%   SAMPLERATE        - Sampling rate
%   AMPLITUDES        - Filter amplitude
%   FREQUENCIES       -	Filter frequencies
%   FILTERORDER       - Filter order
%   DESIGNMETHOD      - Filter design method based on frequency and
%                       magnitude values
%   
%   CONFIGPARAMS, a structure containing the following test parameters:
%   SPS             - Samples per symbol
%   SYMBOLRATE      - Symbol rate
%   BITSPERBYTE     - Bits per byte
%   PHYMODE         - Physical layer transmission mode
%   TESTSEQIDS      - Type of test sequence(s)
%   TESTSEQID       - Test sequence
%   NONPDULEN       - Length of BLE packet excluding PDU
%   DISCARDSTARTLEN - Number of bits to discard at the start of the packet
%   DISCARDENDLEN   - Number of bits to discard at the end of the packet
%   PREAMBLELEN     - Length of the preamble
%   CODINGFACTOR    - FEC Coding scheme
%   NUMOFTESTSEQS   - Number of test sequence
%   SAMPLERATE      - Sampling rate

%   Copyright 2019 The MathWorks, Inc.

% Get test parameters based on test ID
[bwMultFactor,configParams] = getTestParams(testID,sps);

% Design channel filter
filterOrder = 30;
[filterAmps,filterFreqs,sampleRate] = getFilterAmpFreq(bwMultFactor,sps);
filtParams = designfilt('arbmagfir', 'FilterOrder', filterOrder,...
                    'Frequencies', filterFreqs, 'Amplitudes',filterAmps,...
                    'SampleRate', sampleRate);
end

function [bwMultFactor,configParams] = getTestParams(testID,sps)
% Get test parameters based on test ID  
    configParams.sps = sps;
    configParams.symbolRate = 1e6; % In Hz
    configParams.bitsPerByte = 8;    % Number of bits per byte
    bwMultFactor = 1;
    crcLen = 24;
    accessAddLen = 32;
    headerLen = 16;
    termField1Len = 0;
    termField2Len = 0;
    codedFieldLen = 0;
    codingFactor = 1;
    switch testID
        case 'RF-PHY/TRM/BV-06-C'  % Offset and Drift Test
            configParams.phyMode = 'LE1M';
            configParams.testSeqIds = 2;
            configParams.testSeqId(1,:) = '10101010';
            preambleLen = 8;
            bitOffset1 = 1; % Number of bits to be discarded from the start of the payload
            bitOffset2 = 0; % Number of bits to be discarded from the end of the payload, 0 value indicates no need to discard
            configParams.intervalDuration = 10; 
        case 'RF-PHY/TRM/BV-09-C'   % Modulation Test
            configParams.phyMode = 'LE1M';
            configParams.testSeqIds = [1,2];
            configParams.testSeqId(1,:) = '00001111';
            configParams.testSeqId(2,:) = '10101010';
            preambleLen = 8;
            bitOffset1 = 4; % Number of bits to be discarded from the start of the payload
            bitOffset2 = 4; % Number of bits to be discarded from the end of the payload
        case 'RF-PHY/TRM/BV-11-C'   % Modulation Test
            configParams.phyMode = 'LE2M';
            bwMultFactor = 2;
            configParams.symbolRate = 2e6; 
            configParams.testSeqIds = [1,2];
            configParams.testSeqId(1,:) = '00001111';
            configParams.testSeqId(2,:) = '10101010';
            preambleLen = 16;
            bitOffset1 = 4; % Number of bits to be discarded from the start of the payload
            bitOffset2 = 4; % Number of bits to be discarded from the end of the payload          
        case 'RF-PHY/TRM/BV-12-C'   % Offset and Drift Test
            configParams.phyMode = 'LE2M';
            configParams.testSeqId(1,:) = '10101010';
            bwMultFactor = 2;
            configParams.symbolRate = 2e6;
            configParams.testSeqIds = 2;
            preambleLen = 16;
            bitOffset1 = 1; % Number of bits to be discarded from the start of the payload
            bitOffset2 = 0; % Number of bits to be discarded from the end of the payload, 0 value indicates no need to discard
            configParams.intervalDuration = 20; 
        otherwise%'LE125K'
            configParams.phyMode = 'LE125K';
            configParams.testSeqIds = 4;
            preambleLen = 80;
            termField1Len = 3;
            termField2Len = 3;
            codedFieldLen = 2;
            codingFactor = 8;
            configParams.testSeqId(1,:) = '11111111';
            if(strcmp(testID,'RF-PHY/TRM/BV-13-C')) % Modulation Test
                bitOffset1 = 30; % Number of bits to be discarded from the start of the payload
                bitOffset2 = 34; % Number of bits to be discarded from the end of the payload
            else % Offset and Drift Test
                bitOffset1 = 26; % Number of bits to be discarded from the start of the payload
                bitOffset2 = -3; % Number of bits to be discarded from the end of the payload
                configParams.intervalDuration = 16; 
            end
    end
    configParams.nonPDULen = preambleLen+(accessAddLen+headerLen+crcLen+termField1Len+termField2Len+codedFieldLen)*codingFactor;
    configParams.discardStartLen = preambleLen+(accessAddLen+headerLen+termField1Len+codedFieldLen+bitOffset1)*codingFactor;
    configParams.discardEndLen = (bitOffset2+crcLen+termField2Len)*codingFactor;
    configParams.preambleLen = preambleLen;
    configParams.codingFactor = codingFactor;
    configParams.numOfTestSeqs = length(configParams.testSeqIds);
    configParams.sampleRate = configParams.symbolRate*sps;
end

function [filterAmps,filterFreqs,sampleRate] = getFilterAmpFreq(bwMultFactor,sps)
    % Get filter frequencies and corresponding amplitudes
    minChnlBandwidth = 2e6; % Minimum channel bandwidth, in Hz
    sampleRate = 2*sps*minChnlBandwidth*bwMultFactor; % Consider two sided bandwidth based on samples per symbol

    freqVector = [550e3 650e3 1e6 2e6]*sps*bwMultFactor; % in Hz
    attenVector = [0.25 0 -0.25 -3 -14 -44]; % in dB
    freqInterval = (sps*bwMultFactor)*50e3; % GCD for passband and other attenuation frequencies

    % Get filter parameters
    attenVectorLin = db2mag(attenVector); % Linear scale
    filterFreqs = 0:freqInterval:freqVector(end);
    freqVectorDiff = diff(freqVector);
    attenVectorLinDiff = diff(attenVectorLin(3:end)); 
    slopeVector = attenVectorLinDiff./freqVectorDiff;
    slopeInterval = freqVectorDiff/freqInterval;
    amplitudes = zeros(1,sum(slopeInterval));
    temp = 0;
    for ii = 1:length(slopeVector)
        slopeTemp = slopeVector(ii);
        x1 = freqVector(ii);
        x2 = freqVector(ii+1);
        y1 = attenVectorLin(ii+2);
        x = x1+freqInterval:freqInterval:x2;
        y = slopeTemp*(x-x1)+y1;
        amplitudes(temp+1:temp+slopeInterval(ii)) = y;
        temp = slopeInterval(ii);
    end
    passbandAmplitudes = repmat(attenVectorLin(1:3),1,(length(0:freqInterval:freqVector(1))/3)); % Generate filter amplitudes in pass band
    filterAmps = [passbandAmplitudes amplitudes];
end
