function hCreateWLANNetworkModel(modelname, numberOfNodes)
%hCreateWLANNetworkModel Create a WLAN network with given number of nodes
%
%   This is an example helper function.
%
%   hCreateWLANNetworkModel(MODELNAME, NUMBEROFNODES) creates a network of
%   WLAN nodes with the abstracted physical layer, with the specified
%   number of nodes in the network.
%
%   MODELNAME specifies the name of the new network model.
%
%   NUMBEROFNODES specifies the number of nodes.

%   Copyright 2019 The MathWorks, Inc. 

% Node subsystem used for creating the network
exampleBlockPath = 'WLANMultiNodeAbstractedPHYModel/Node1';

% Simulation time
simTime = '0.1';

% Initialize destinations for all the nodes (0 indicates passive receiver)
destinationNodes = zeros(1, numberOfNodes);
destinationNodes(1) = 2; % Set destination for 1st node as Node2
% Set destination for 1/10th of the nodes as Node1
for idx = 2:floor(numberOfNodes/10)
    destinationNodes(idx) = 1;
end

% Channel configuration
paramPacketRxRange = '10000';

% PHY receiver configuration
paramEDThreshold = '-82'; % in dBm
paramRxGain = '0'; % in dB
paramRxNoiseFigure = '7'; % in dB
paramPHYAbstraction = 'TGax Evaluation Methodology Appendix 1'; % 'TGax Simulation Scenarios MAC Calibration' | 'TGax Evaluation Methodology Appendix 1'

% PHY transmitter configuration
paramTxPower = '15';
paramTxGain = '0';

% To create a new model, copy the example model to retain the
% model initialization settings
if exist(modelname, 'file') ~= 4
    success = copyfile('WLANMultiNodeAbstractedPHYModel.slx', [modelname '.slx']);
    if ~success
        error('Failed to create the requested model, copying the example-file failed.');
    end
else
    error(['A Simulink model already exists with the name ' modelname '.slx']);
end
load_system(modelname)
Simulink.BlockDiagram.deleteContents(modelname); % Clear the new model

newBlockPath = [modelname '/Node1'];
% Copy a node subsystem from the example model
add_block(exampleBlockPath, newBlockPath, 'MakeNameUnique', 'on');

% Number of blocks in a row
noOfBlksInRow = 10;
% Offset between 2 blocks
widthoffset = 50;
heightoffset = 80;
% Get current position of a given block
currentPos = get_param(newBlockPath, 'Position');
% Get height from current position
height = currentPos(4)-currentPos(2);
% Get width from current position
width = currentPos(3)-currentPos(1);

for idx = 1:numberOfNodes-1
    % Calculate X and Y positions for a new block
    x = currentPos(1) + widthoffset*(mod(idx, noOfBlksInRow));
    y = currentPos(2) + heightoffset*(floor((idx)/noOfBlksInRow));
    % Position of a new block
    position = [x y x+width y+height];
    % Add given block to the given block with unique names and positions
    add_block(newBlockPath,newBlockPath,'MakeNameUnique','on','Position',position);
end

% Add the node position allocator, visualization, and channel DSM blocks
% required for the model configuration
add_block('WLANMultiNodeAbstractedPHYModel/Node Position Allocator', [modelname '/Node Position Allocator'])
add_block('WLANMultiNodeAbstractedPHYModel/Visualizer', [modelname '/Visualizer'])
add_block('WLANMultiNodeAbstractedPHYModel/Channel Matrix', [modelname '/Channel'])
set_param(modelname, 'StopTime', simTime); % Set simulation time

for idx = 1:numberOfNodes
    nodePath = [modelname '/Node' num2str(idx)];
    
    % Configure application
    if destinationNodes(idx)
        set_param([nodePath '/Application Traffic Generator'],'DestinationName',['Node' num2str(destinationNodes(idx))]);
        set_param([nodePath '/Application Traffic Generator'],'ApplicationState','On');
    else
        set_param([nodePath '/Application Traffic Generator'],'ApplicationState','Off');
        set_param([nodePath '/Application Traffic Generator'],'DestinationName',['Node' num2str(destinationNodes(idx))]);
    end
    
    % Configure channel
    set_param([nodePath '/Statistical Channel'],'PacketRxRange',paramPacketRxRange);
    
    % Configure receiver
    set_param([nodePath '/Abstracted PHY Receiver'],'EDThreshold',paramEDThreshold);
    set_param([nodePath '/Abstracted PHY Receiver'],'RxGain',paramRxGain);
    set_param([nodePath '/Abstracted PHY Receiver'],'RxNoiseFigure',paramRxNoiseFigure);
    set_param([nodePath '/Abstracted PHY Receiver'],'PHYAbstraction',paramPHYAbstraction);
    
    % Configure transmitter
    set_param([nodePath '/Abstracted PHY Transmitter'],'TxPower',paramTxPower);
    set_param([nodePath '/Abstracted PHY Transmitter'],'TxGain',paramTxGain);
end

% Save the model
save_system(modelname);
open_system(modelname);
end