function [y,bits] = ehtSIG(cfgEHT,varargin)
%ehtSIG EHT SIG Field (EHT-SIG)
%
%   [Y,BITS] = ehtSIG(CFGEHT) generates the EHT SIG field (EHT-SIG)
%   time-domain signal for the EHT MU transmission format. Specify the
%   source of EHT-SIG bits using the <a href="matlab:help('ehtMUConfig/EHTSIGBitsSource')">EHTSIGBitsSource</a> property of 
%   <a href="matlab:help('ehtMUConfig')">ehtMUConfig</a> configuration object.
%
%   Y is the time-domain EHT-SIG signal. It is a complex matrix of size
%   Ns-by-Nt where Ns represents the number of time-domain samples and Nt
%   represents the number of transmit antennas.
%
%   BITS are the EHT-SIG signaling bits. For OFDMA it is of type int8,
%   binary matrix of size (NDBPS*NumSym)-by-NUM80-by-NumContentChannels,
%   where NDBPS are the number of data bits per symbols, NumSym are the
%   number of EHT-SIG symbols. NUM80 is the number of 80 MHz frequency
%   segments. NumContentChannels is one for 20 MHz and two for 40 MHz, 80
%   MHz, 160 MHz, or 320 MHz channel bandwidth. For non-OFDMA, the number of
%   BITS is a binary matrix of size (NDBPS*NumSym)-by-1-by-NumContentChannels. 
%   You can calculate the number of EHT-SIG bits using <a href="matlab:help('ehtMUConfig/getNumEHTSIGBits')">getNumEHTSIGBits</a>
%   method.
%
%   CFGEHT is the format configuration object of type <a
%   href="matlab:help('ehtMUConfig')">ehtMUConfig</a>
%
%   Y = ehtSIG(CFGEHT,OSF) generates a signal oversampled by the
%   oversampling factor OSF. When not specified, 1 is assumed.
%
%   Example: Generate an EHT-SIG field for a 320 MHz EHT MU PPDU format.
%
%     cfgEHT = ehtMUConfig('CBW320');
%     y = ehtSIG(cfgEHT);
%     plot(abs(y));
%
%   See also ehtMUConfig, ehtSTF.

%   Copyright 2020-2021 The MathWorks, Inc.

validateattributes(cfgEHT,{'ehtMUConfig'},{'scalar'},mfilename,'EHT MU format configuration object');

osf = 1;
if nargin>1
    osf = varargin{1};
end

[codingInfo,contentChannelUsers80MHz] = ehtSIGCodingInfo(cfgEHT);
Nsym = codingInfo.NumSIGSymbols; % Number of EHT-SIG symbols
chanBW = cfgEHT.ChannelBandwidth;
numSegments = size(contentChannelUsers80MHz,1); % Number of segments

cfgOFDM = wlan.internal.hePreHEOFDMConfig(chanBW);
Nfft = cfgOFDM.FFTLength;
cpLen = cfgOFDM.CyclicPrefixLength;
chBW = wlan.internal.cbwStr2Num(cfgEHT.ChannelBandwidth);
num20 = cfgOFDM.NumSubchannels;
numEHTSIGBits = codingInfo.NumSIGBits;

% Number of 20 MHz repetitions within a 80 MHz subblock
switch chBW
    case 20
        num20Repetitions = 1; 
    case 40
        num20Repetitions = 2;
    otherwise 
        num20Repetitions = 4;
end

if cfgEHT.IsOFDMA
    N = ceil(num20Repetitions/2); % Number of content channel repetitions
    N_Seq = repmat([1 2],1,N);
    N_Seq = N_Seq(1:num20Repetitions); % Repeat within a 80 MHz subblock
else
    N = ceil(num20/2); % Number of content channel repetitions
    N_Seq = repmat([1 2],1,N);
    N_Seq = N_Seq(1:num20); % Repetition sequence
    num20Repetitions = num20; % There is a single block in non-OFDMA, SU or NDP
end

if ~strcmp(cfgEHT.EHTSIGBitsSource,'User-defined')
    % Generate EHT-SIG bits
    ehtsigBits = randomEHTSIGBits(cfgEHT.EHTSIGBitsSource,cfgEHT.EHTSIGBitsSeed,numEHTSIGBits);
else % Repeat/cut/ EHT-SIG bits
    ehtsigBits = wlan.internal.parseInputBits(int8(cfgEHT.EHTSIGBits),numEHTSIGBits);
end

% Reshape bits by number of 80 MHz segment
numCChs = codingInfo.NumContentChannels;
numBitsPer80MHzSegment = numEHTSIGBits/numSegments; % Number of bits in 80 MHz frequency segment
numBitsPerContentCh = numBitsPer80MHzSegment/numCChs; % Number of bits per content channel within a 80 MHz segment
ehtSigBits = reshape(ehtsigBits,numBitsPerContentCh,numSegments,numCChs); % bitsPerContentCh-by-Num80-by-NumContentChannel

bits = int8(ehtSigBits); % Set output bits
dataSym = zeros(52*num20,Nsym); % NSD is fixed i.e. 52
% Interleave parameters
NCBPSSI = codingInfo.NCBPS/codingInfo.NSS;
ruSize = 56; % RUSize 56 is fixed as defined in IEEE P802.11ax/D4.1, Table 27-33

for i=1:numSegments
    % Encode each content channel within a 80 MHz frequency segment
    encodedBits = wlanBCCEncode(squeeze(ehtSigBits(:,i,:)),codingInfo.Rate);
    
    % Interleave all bits together, as effectively they will be split at symbol boundaries
    interleavedBits = wlan.internal.heBCCInterleave(encodedBits(:),ruSize,codingInfo.NBPSCS,NCBPSSI,codingInfo.DCM);
    
    % Reshape to form OFDM symbols, NCBPS-by-numSym-by-numContentChs
    interleavedSym = reshape(interleavedBits,codingInfo.NCBPS,Nsym,codingInfo.NumContentChannels);
    
    % Constellation mapping (with optional DCM),
    mappedSym = wlan.internal.heConstellationMap(interleavedSym,codingInfo.NBPSCS,codingInfo.DCM); % 52-by-numSym-by-numContentChs

    if codingInfo.CompressionMode==1 % Single user or NDP
        dataSym((1:52*num20)+(52*num20)*(i-1),:) = repmat(mappedSym,num20,1); % 52*num20-by-numSym
    else 
        % Replicate over 20 MHz segment
        dataSym((1:52*num20Repetitions)+(52*num20Repetitions)*(i-1),:) = reshape(permute(mappedSym(:,:,N_Seq),[1 3 2]),[],Nsym,1); % 52*num20Repetitions-by-numSym
    end 
end

z = 4; % Pilot symbols offset
% Pilots across content channels
pilotSym = repmat(wlan.internal.nonHTPilots(Nsym,z),num20,1); % num20-by-numSym 

% Map data and pilots
sym = complex(zeros(Nfft,Nsym));
sym(cfgOFDM.DataIndices,:) = dataSym;
sym(cfgOFDM.PilotIndices,:) = pilotSym;

% Apply gamma rotation per 20 MHz frequency segment
[sym,scalingFactor] = ehtPreEHTFieldMap(sym,cfgOFDM.NumTones,cfgEHT);

if ~cfgEHT.EHTSIGMCS==15
    % Add Gamma scaling per content channel
    GammaRef = ones(Nfft,1);
    dataInd = reshape(cfgOFDM.DataIndices,[],num20);
    % Negate every second data symbol in the second half of each 20 MHz channel
    GammaRef(dataInd(end/2+1+1:2:end,:)) = -1;
    sym = bsxfun(@times,sym,GammaRef);
end

% OFDM modulate
if osf>1
    padding = zeros((osf-1)*Nfft/2,Nsym,cfgEHT.NumTransmitAntennas,'like',sym);
    sym = [padding; sym; padding];
    scalingFactor = scalingFactor*osf;
    cpLen = cpLen*osf;
end
y = wlan.internal.wlanOFDMModulate(sym,cpLen)*scalingFactor;

end

function ehtsigBits = randomEHTSIGBits(randomStream,seed,numBits)
% randomEHTSIGBits Generate random EHT-SIG field bits
    persistent stream

    if strcmp(randomStream,'mt19937ar with seed')
        if isempty(stream)
            stream = RandStream('mt19937ar');
        end
        % Use same seed when generating each packet
        reset(stream,seed);
        ehtsigBits = randi(stream,[0 1],numBits,1,'int8');
    else
        % Use global stream
        ehtsigBits = randi([0 1],numBits,1,'int8');
    end
end