function commwman80216_2009_init(block,action,varargin)
%% COMMWMAN80216_2009_INIT Parameter settings for commwman80216_2009 models.
%
%   Set up commonly used parameters ('p' and 'pfixed' structure) for 
%   IEEE 802.16-2009 models.

%   Copyright 2011-2021 The MathWorks, Inc.

modelName = bdroot;

switch(action)         
    case 'rateID'
        % Mask control for useFixedRateID
        % Get variables from mask
        En   = get_param(block, 'MaskEnables');
        Vals = get_param(block, 'MaskValues');
        Vis  = get_param(block, 'MaskVisibilities');
        
        [idxSNRthres,idxAdaptRateID, idxCodeRate1, idxModulation1, idxCodeRate2, ixdModulation2] = dspGetMaskParamIdx(block, ...
            'SNRthres',...        
            'adaptRateID',...
            'codeRate1', ...
            'modulation1',...
            'codeRate2',...
            'modulation2');
        if strcmp(Vals{idxAdaptRateID}, 'on')
            rateIDFlag = 'off';
            Vis{idxSNRthres}   = 'on';
            En{idxSNRthres}    = 'on';
        else
            rateIDFlag = 'on';
            Vis{idxSNRthres}   = 'off';
            En{idxSNRthres}    = 'off';
        end
        Vis{idxCodeRate1}   = rateIDFlag;
        Vis{idxModulation1} = rateIDFlag;
        Vis{idxCodeRate2}   = rateIDFlag;
        Vis{ixdModulation2} = rateIDFlag;
        En{idxCodeRate1}    = rateIDFlag;
        En{idxModulation1}  = rateIDFlag;
        En{idxCodeRate2}    = rateIDFlag;
        En{ixdModulation2}  = rateIDFlag;
        
        %-- Update parameters
        set_param(block, 'MaskEnables', En, 'MaskVisibilities', Vis); 
        
    case 'init'
        % called from model preload callback
        p = init_parameterOrder();
        Initialize_Parameters(0, 0,p);
        
    case 'init2'
        % called from Model Parameters block
        p  = init_parameterOrder();
        
        % get the simulation settings
        [numSym,subChanRange1, subChanRange2,SNRthres,chanBW,g,codeRate1,modulate1,codeRate2,modulate2,useAdaptRateId, segment] = deal(varargin{:});
        
        % check numSym
        if ((floor(bitsra(numSym,1))*2 ~= numSym)||...
                (numSym>p.numSymMax))
           error(message('comm:commwman80216_2009_init:InvalidNumOfSymPerBurst'));
        end
        set_param([modelName '/OFDMA Symbol Packing/numsymbol/Constant'], 'value', num2str(numSym));
                
        % Per table 649, Channel bandwidth is from 1.25MHz~28MHz
        % Also from Table 613, 8 bits can be used to specify Channel
        % bandwidth in units of 1.25 kHz
        if (chanBW >= 33)
            error(message('comm:commwman80216_2009_init:InvalidChanBW'));
        end
        
        % SNRthres parameter must be a 6-element vector
        if (length(SNRthres) ~= 6)
            error(message('comm:commwman80216_2009_init:InvalidSNRThreshold'));
        end
        
        % Subchannel parameter check       
        subchan1 = subChanRange1;        
        subchan2 = subChanRange2;
        
        if (subchan1(1)>=subchan1(2))||(subchan2(1)>=subchan2(2))
                    error(message('comm:commwman80216_2009_init:InvalidSubChanIndex'));
        end        
                
        if (subchan1(1)==subchan2(1))||...
           (subchan1(1)==subchan2(2))||...
           (subchan1(2)==subchan2(1))||...           
           (subchan1(2)==subchan2(1))
                    error(message('comm:commwman80216_2009_init:InvalidSubChanIndex'));
        end        
        
        if (subchan1(1)<subchan2(1))&&...
           (subchan1(2)>=subchan2(1))
                    error(message('comm:commwman80216_2009_init:InvalidSubChanIndex'));
        end        
        
        if (subchan2(1)<subchan1(1))&&...
           (subchan2(2)>=subchan1(2))
                    error(message('comm:commwman80216_2009_init:InvalidSubChanIndex'));
        end
        
        if (subchan1(2)>29)||...
           (subchan2(2)>29)||...
           (subchan1(1)<0)||...
           (subchan2(1)<0)||...
           (subchan1(1)>subchan1(2))||...
           (subchan2(1)>subchan2(2))
                    error(message('comm:commwman80216_2009_init:InvalidSubChanOver30'));  
        end 
        set_param([modelName '/OFDMA Symbol Packing/subchann1/Constant'], 'value', sprintf('[%d %d]', subchan1(1)+1, subchan1(2)+1));
        set_param([modelName '/OFDMA Symbol Packing/subchann2/Constant'], 'value', sprintf('[%d %d]', subchan2(1)+1, subchan2(2)+1));
            
        p.rateswitch      = useAdaptRateId;
        p.SNRthres        = SNRthres;
        p.numDataOFDMASymbols = numSym; 
        p.subChanRange1   = subChanRange1+1; % +1 to convert to 1 based
        p.subChanRange2   = subChanRange2+1; % +1 to convert to 1 based
        p.g               = str2num(g); %#ok
        
        switch segment
            case 'Segment 0'
                p.Segment         = 0;
            case 'Segment 1'
                p.Segment         = 1;
            case 'Segment 2'
                p.Segment         = 2;
        end
        
        % ----------------------------------------------------------------
        % User API (for user1 and user2):
        %   ---- Specify the FEC coding rate
        %   ---- Specifying the puncture vector based on the coding rate
        %   ---- if QAM, also specify M and constellation
        %
        % code rate ID:
        %             QPSK       16 QAM     64 QAM
        %  1/2         0           8          12
        %  2/3        N/A         N/A         13
        %  3/4         2           10         14
        % ----------------------------------------------------------------
        switch codeRate1
            case '1/2'
                p.punctureVector1 = [1;1];
                RateID1 = 0;
            case '2/3'
                p.punctureVector2 = reshape([1 0;1 1], 4, 1);
                RateID1 = 1;
            case '3/4'
                p.punctureVector1 = reshape([1 0 1;1 1 0], 6, 1);
                RateID1 = 2;
        end
        
        switch modulate1
            case 'QPSK'
            case '16 QAM'
                p.QAMM1     = 16;
                p.QAMConstellation1 = [13 12 14 15 9 8 10 11 1 0 2 3 5 4 6 7];
                RateID1 = RateID1 + 8;
            case '64 QAM'
                p.QAMM1     = 64;
                p.QAMConstellation1 = [59 58 56 57 61 60 62 63 51 50 48 49 53 52 54 55 35 34 32 33 ...
                    37 36 38 39 43 42 40 41 45 44 46 47 11 10 8 9 13 12 14 15 3 ...
                    2 0 1 5 4 6 7 19 18 16 17 21 20 22 23 27 26 24 25 29 28 30 31];
                RateID1 = RateID1 + 12;
        end
        
        switch codeRate2
            case '1/2'
                p.punctureVector2 = [1;1];
                RateID2 = 0;
            case '2/3'
                p.punctureVector2 = reshape([1 0;1 1], 4, 1);
                RateID2 = 1;
            case '3/4'
                p.punctureVector2 = reshape([1 0 1;1 1 0], 6, 1);
                RateID2 = 2;
        end
        
        switch modulate2
            case 'QPSK'
            case '16 QAM'
                p.QAMM2      = 16;
                p.QAMConstellation2 = [13 12 14 15 9 8 10 11 1 0 2 3 5 4 6 7];
                RateID2 = RateID2 + 8;
            case '64 QAM'
                p.QAMM2      = 64;
                p.QAMConstellation2 = [59 58 56 57 61 60 62 63 51 50 48 49 53 52 54 55 35 34 32 33 ...
                    37 36 38 39 43 42 40 41 45 44 46 47 11 10 8 9 13 12 14 15 3 ...
                    2 0 1 5 4 6 7 19 18 16 17 21 20 22 23 27 26 24 25 29 28 30 31];
                RateID2 = RateID2 + 12;
        end
        
        if (RateID1 == 1) || (RateID1 == 9)||...
           (RateID2 == 1) || (RateID2 == 9)
            error(message('comm:commwman80216_2009_init:InvalidRate'));
        end        
        p.BW    = chanBW*1e6;   % the nominal channel bandwidth in Hz 
        Initialize_Parameters(RateID1, RateID2,p);
end

function p = init_parameterOrder()
% Default settings
p.numDataOFDMASymbols  = 2;  % Number of OFDMAsymbols per slot
p.numFCHOFDMASymbols   = 0;
p.numPreamOFDMASymbols = 0;
p.subChanRange1        = [1 6];
p.subChanRange2        = [7 10];
p.numDataUser1         = 0;
p.numDataUser2         = 0;
p.Segment              = 0;
p.SNRthres             = [2 10 20 30 40 50 60];
p.DLPermBase           = 0;
p.DLMAP_rep            = 0;
p.DLMAP_len            = 0;
p.fch                  = [];
p.g                    = 1/8;
p.PreambleIndices      = [];
p.Preamble             = [];
p.punctureVector1      = [1;1];
p.punctureVector2      = [1;1];
p.rateID1              = 0;
p.rateID2              = 0;
p.rateswitch           = 0;
p.rxCPIndices          = [];
p.ts                   = 0;
p.totOFDMSym           = 0;
p.txCPIndices          = [];
p.numSymMax            = 10;
p.BW                   = 3.5*1e6;  % the nominal channel bandwidth in Hz
p.rateswitch           = 0;        % 0:use detected rateIDs;1:use fixed rateIDs
    
function Initialize_Parameters(RateID1, RateID2,p)
switch RateID1
    case 0
        p.rateID1 = 1;
    case 2
        p.rateID1 = 2;
    case 8
        p.rateID1 = 3;
    case 10
        p.rateID1 = 4;
    case 12
        p.rateID1 = 5;
    case 13
        p.rateID1 = 6;
    case 14
        p.rateID1 = 7;
end

switch RateID2
    case 0
        p.rateID2 = 1;
    case 2
        p.rateID2 = 2;
    case 8
        p.rateID2 = 3;
    case 10
        p.rateID2 = 4;
    case 12
        p.rateID2 = 5;
    case 13
        p.rateID2 = 6;
    case 14
        p.rateID2 =7;
end

% Primitive parameters characterize the OFDMA symbol(Section 8.4.2.3)
% Sampling factor 8.4.2.3
% This parameter, in conjunction with BW and Nused determines
% the subcarrier spacing, and the useful symbol time.
% 
if mod(p.BW, 1.75e6)     == 0
    n = 8/7;
elseif mod(p.BW, 1.5e6)  == 0
    n = 28/25;
elseif mod(p.BW, 1.25e6) == 0
    n = 28/25;
elseif mod(p.BW, 2.75e6) == 0
    n = 28/25;
elseif mod(p.BW, 2e6)    == 0
    n = 28/25;
else
    n = 8/7;
end

p.DLPermBase      = 0;

% Fixed for 1024 FFT
% -------------------------------------------------------
pfixed.nfft             = 1024; % Number of FFT bins
pfixed.nused            = 840;  % Number of used subcarriers including pilots
pfixed.pLeftGuard       = 86;   % left guard for the preamble
pfixed.pRightGuard      = 85;   % right guard for the preamble
pfixed.numPerChannel    = 24;
pfixed.FCHlen           = 24;   % FCH length
pfixed.nused            = 840;  
pfixed.numDataSym       = 720;  % Number of data symbols in OFDMA symbol
                                % exclude 2 pilots in each cluster
pfixed.numCluster       = 60;
pfixed.numSubchannel    = 30;
pfixed.Ldc              = 12;  % number of data carriers in a cluster
pfixed.Lsc              = 14;  % number of subcarriers in a cluster
% -------------------------------------------------------

% Derived parameters (Section 8.4.2.4)
Fs      = floor(n*p.BW/8000)*8000;        % Sampling Frequency
df      = Fs/pfixed.nfft;                 % Subcarrier Spacing
Tb      = 1/df;                           % Useful Symbol time
Tg      = p.g*Tb;                         % Cyclic prefix time
Tsymbol = Tg + Tb;                        % OFDM symbol time
p.ts    = Tsymbol/pfixed.nfft;            % Sampling time, (==(1+g)/Fs)

% For downlink PUSC using the distributed subcarrier permutation (defined
% in 8.4.6.1.2.1),
p.numFCHOFDMASymbols   = 2;   % Number of FCH/DL-MAP OFDMAsymbols per slot
p.numPreamOFDMASymbols = 1;   % Number of preamble OFDMA symbols
p.totOFDMSym = p.numPreamOFDMASymbols + p.numFCHOFDMASymbols + p.numDataOFDMASymbols;

p  = FillPreamble(p, pfixed);
p  = FillFCH(p,pfixed);
p  = FillPilots(p);

% Separate preamble, FCH/DL-MAP, and Data
p.txCPIndices = [pfixed.nfft*(1-p.g)+1:pfixed.nfft  1:pfixed.nfft];
p.rxCPIndices = pfixed.nfft*p.g+1:pfixed.nfft*(1+p.g);

% Multi-user parameters
subchannelsUser1   = p.subChanRange1(2)- p.subChanRange1(1)+1;
subchannelsUser2   = p.subChanRange2(2)- p.subChanRange2(1)+1;
p.numDataUser1     = subchannelsUser1*pfixed.numPerChannel; % Number of data symbols for user1
p.numDataUser2     = subchannelsUser2*pfixed.numPerChannel; % Number of data symbols for user2


% Assign variable to base workspace
assignin('base', 'prm80216_2009', p);

pfixed.DLMAP_len        = p.DLMAP_len;
pfixed.DLMAP_rep        = p.DLMAP_rep;
pfixed.DLPermBase       = p.DLPermBase;
pfixed.PreambleLen      = 71*4;

% Table 310a: 1k FFT OFDMA DL carrier allocation -- PUSC
pfixed.leftGuard        = 92;  % left guard
pfixed.rightGuard       = 91;  % right guard for FCH

% Interleaving index tables
%                            Table  7     6     5     4     3     1
% QPSK-1/2:  [6 5 4 3 2 1]*48*2 = [576   480   384   288   192    96]
% QPSK-3/4:  [4 3 2 1]*72*4/3   = [            384   288   192    96]
% 16 QAM-1/2:[3 2 1]*96*2       = [576         384         192]
% 16 QAM-3/4:[2 1]*144*4/3      = [            384         192]
% 64 QAM-1/2:[2 1]*144*2        = [576               288]
% 64 QAM-2/3: 192*3/2           =                    288
% 64 QAM-3/4: 216*4/3           =                    288
pfixed.intrlvTable = zeros(576,6);
pfixed.intrlvTable(1:96,1)  = commwman80216_2009_intrlvr(96, 1, 1);
pfixed.intrlvTable(1:192,2) = commwman80216_2009_intrlvr(192, 1, 1);
pfixed.intrlvTable(1:288,3) = commwman80216_2009_intrlvr(288, 1, 1);
pfixed.intrlvTable(1:384,4) = commwman80216_2009_intrlvr(384, 1, 1);
pfixed.intrlvTable(1:480,5) = commwman80216_2009_intrlvr(480, 1, 1);
pfixed.intrlvTable(:,6)     = commwman80216_2009_intrlvr(576, 1, 1);

assignin('base', 'prm80216_2009fixed', pfixed);

function p = FillPreamble(p, pfixed)
% Preamble sequence for 1k FFT per Section 8.4.6.1.1 Table 438
% For 1K FFT, the PN sequence is 71 char long. There are three segments.
% Index  0: IDcell 0, Segment 0 --- stored in preamble(:1)
% Index  1: IDcell 1, Segment 0 --- stored in preamble(:2)
% Index 31: IDcell 0, Segment 1 --- stored in preamble(:3)
% Index 32: IDcell 1, Segment 1 --- stored in preamble(:4)
% Index 64: IDcell 0, Segment 2 --- stored in preamble(:5)
% Index 65: IDcell 1, Segment 2 --- stored in preamble(:6)
% 
IDcell  = 0;
assert(IDcell<2, 'IDcell must be less than 2 for this model');
Clength = 71;

% All 6 Preamble sequences out in char format
preamble = zeros(Clength,6);
preamble(:,1) = 'A6F294537B285E1844677D133E4D53CCB1F182DE00489E53E6B6E77065C7EE7D0ADBEAF';
preamble(:,2) = '668321CBBE7F462E6C2A07E8BBDA2C7F7946D5F69E35AC8ACF7D64AB4A33C467001F3B2';
preamble(:,3) = '52849D8F020EA6583032917F36E8B62DFD18AD4D77A7D2D8EC2D4F20CC0C75B7D4DF708';
preamble(:,4) = 'CC53A152209DEC7E61A06195E3FA633076F7AE1BAFFE83CE565087C0507BA596E0BD990';
preamble(:,5) = 'D27B00C70A8AA2C036ADD4E99D047A376B363FEDC287B8FD1A7794818C5873ECD0D3D56';
preamble(:,6) = 'E7FDDCEED8D31B2C0752D976DE92BEA241A713CF818C274AA1C2E3862C7EB7023AF35D4';

% Convert Preamble sequences into bits
pp     = zeros(Clength*4,6); %4--char
ppTemp = zeros(Clength,4,6);
for j = 1:6
    ppTemp(:,:, j) = dec2bin(hex2dec(preamble(:,j)));
    bj = ppTemp(:,:,j);
    for i=1:Clength*4
        pp(i, j) = hex2dec(bj(i));
    end
end

p.Preamble = pp(:, (p.Segment*2+IDcell+1));
L_data        = Clength*2*3;
p.PreambleIndices = [pfixed.pLeftGuard+1:(L_data+pfixed.pLeftGuard) ...
    (L_data+pfixed.pLeftGuard+2):(2*L_data+pfixed.pLeftGuard+1)];

function p = FillFCH(p, pfixed)
% -------------------------------------------------------------------------
% The FCH shall be transmitted using QPSK rate 1/2 with 4 repetitions using
% the mandatory coding scheme, the FCH information will be sent on four
% adjacent subchannels with successive logical subchannel numbers. Each
% subchannel contains 24 subcarriers per Section 8.4.4.3 Table 268
% Total of 24 bits:
% Used subchannel bitmap -- 6 bits
%          bit 0: subchannel group 0 (subchannel  0~5)  is used
%          bit 1: subchannel group 1 (subchannel  6~9)  is used
%          bit 2: subchannel group 2 (subchannel 10~15) is used
%          bit 3: subchannel group 3 (subchannel 16~19) is used
%          bit 4: subchannel group 4 (subchannel 20~25) is used
%          bit 5: subchannel group 5 (subchannel 26~29) is used
% Reserved 1 bit (set to zero)
% Repetition_Coding_Indication -- 2 bits
%          00: No repetition coding   on DL-MAP   *
%          01: repetition coding of 2 on DL-MAP
%          10: repetition coding of 4 on DL-MAP
%          11: repetition coding of 6 on DL-MAP
% Coding_Indication  -- 3 bits
%          000:CC    encoding used on DL-MAP    *
%          001:BTC   encoding used on DL-MAP
%          010:CTC   encoding used on DL-MAP
%          011:ZT CC encoding used on DL-MAP
%          100:CC encoding with optional interleaver
%          101:LDPC encoding used on DL-MAP
%          110 to 111:Reserved
% DL_MAP_Length --- 8 bits
% Reserved 4 bit (set to zero)
%

% To simplify, assume FCH+DL_MAP occupies 2 OFDMA symbols
p.DLMAP_len = 248;
p.DLMAP_rep = 4;  % repetition coding of 6 on DL-MAP

USB = '111111'; % Used subchannel bitmap -- 6 bits
RCI = '100';    % Reserved 1 bit and Repetition_Coding_Indication -- 2 bits
CI  = '000';    % Coding_Indication  -- 3 bits
RESERVED = '0000';   % Reserved 4 bit (set to zero)
fch_bin = [RESERVED dec2bin(p.DLMAP_len) CI RCI USB];
fch = zeros(1, pfixed.FCHlen);
for i = 1:pfixed.FCHlen
    fch(i) = bin2dec(fch_bin(i));
end
p.fch = fch';

function p = FillPilots(p)
% Fill the pilot info based on 8.4.9.4.1. The value of the pilot 
% modulation, on carrier k, shall be derived from wk in Figure 293.
% Generate pilot vector of 1024. The transmitter and receivers will pick up
% the pilot for the corresponding subcarriers.
%
% The initialization vector of the PRBS generator b10~b0 
% per 8.4.9.4.1 figure 293, assume IDcell as '0'.
%
% Set 'SamplesPerFrame' to be 2048 because this is the maximum length of
% uncorrelated PN sequence hpilot can generate
%
p.PRBSInit = [1 1 1 1 int2bit(p.Segment+1,2,0)' 0 0 0 0 0]; 

pnSeq = comm.PNSequence('Polynomial', fliplr([1 0 1 0 0 0 0 0 0 0 0 1]), ...
        'InitialConditions', p.PRBSInit, ...
        'SamplesPerFrame', 2048, 'OutputDataType', 'logical');  
p.pilot = 1-2*pnSeq();

