%% Clear all the variables in the workspace, close all figure windows
% clear all; close all;
% rng('default');

%% Behavioral Turbo Decoder
% Turbo decoding of soft bits obtained from a noisy constellation
turboFrameSize = 6144;
txBits = randi([0 1],turboFrameSize,1);
codedData = lteTurboEncode(txBits);
txSymbols = lteSymbolModulate(codedData,'QPSK');
noise = 0.5*complex(randn(size(txSymbols)),randn(size(txSymbols)));
rxSymbols = txSymbols + noise;
scatter(real(rxSymbols),imag(rxSymbols),'co'); hold on;
scatter(real(txSymbols),imag(txSymbols),'rx')
legend('Rx constellation','Tx constellation')
softBits = lteSymbolDemodulate(rxSymbols,'QPSK','Soft');
rxBits = lteTurboDecode(softBits);

%% Conversion of Input Frames to Samples
% Convert the input frame to fixed-point
inframes = fi(softBits, 1, 5, 2);

% Settings for whdlframestosamples function
inframesize = size(inframes,1);

% no invalid cycles between samples
idlecyclesbetweensamples = 0;

% number of samples read in at every time step
insamplesize = 3; % encode rate is 1/3

% additional delay in frames for Turbo Decoder output
numTurboIterations = 6;
% approximate latency from Turbo Decoder block
tdlatency = (ceil(turboFrameSize/32)+4)*32;
% additional (approximate) delay in frames for Turbo Decoder output
algframedelay = (2*numTurboIterations + 2)*(ceil(tdlatency/turboFrameSize));
idlecyclesbetweenframes = (inframesize/insamplesize)*algframedelay;

% output is composed of interleaved input samples
% input: S_1 S_2 ... S_n P1_1 P1_2 ... P1_n P2_1 P2_2 ... P2_n
% output: S_1 P1_1 P2_1 S2 P1_2 P2_2 ... Sn P1_n P2_n
interleaveSamples = true;

% Convert frames to samples
[sampleIn, ctrlIn] = ...
    whdlFramesToSamples(inframes, ...
                          idlecyclesbetweensamples, ...
                          idlecyclesbetweenframes, ...
                          insamplesize, ...
                          interleaveSamples);

%% Simulink hardware-targeted model settings
% samples are being fed in at sample time = 1
sampletime = 1;

% Turbo decoder setting
outframesize = size(txBits, 1);

% simulation time - same as total control input
simTime = size(ctrlIn, 1);

% Open the model
modelname = 'TurboDecoderStreamingDataHDLExample';
open_system(modelname);

%% Run the model
sim(modelname);

%% Conversion of Output Samples to Frames
% reformat the logged data to form the sample and control output
sampleOut = squeeze(sampleOut_ts.Data);
ctrlOut = [squeeze(ctrlOut_ts.start.Data) ...
    squeeze(ctrlOut_ts.end.Data) ...
    squeeze(ctrlOut_ts.valid.Data)];
% form frames from output sample and control data
outframes = whdlSamplesToFrames(sampleOut, ctrlOut);
% gather all the bits - expecting only one frame
rxBits_hdl = outframes{:};

%% Verify Output of Simulink Model
% Check number of bit mismatches
numBitsDiff = sum(rxBits_hdl ~= rxBits);
fprintf(['\nLTE Turbo Decoder: Behavioral and ' ...
    'HDL simulation differ by %d bits\n\n'], numBitsDiff);

% close the model and figures
bdclose(modelname);
close all;
