%

% Copyright 2012 The MathWorks, Inc.

classdef BandwidthIncomingTest < coder.rtiostreamtest.Test
%BANDWIDTHINCOMINGTEST determines target to pc link bandwidth
% Makes the target send large amount of data and checks whether the
% data was received correctly. The data is just an eight bit counter
% which wraps around.
%
% Parameters:
%
% pcSize -
% The amount of data that the PC sends in one go (in memory
% chunks)
% targetSize -
% The amount of data the target receives in one go (in memory
% chunks)
% size -
% The total amount of data that will be transmitted between
% the client and the server (in memory chunks)
% skipCheck -
% Whether to check the incoming data for integrity. This is
% disabled by default. Enable it only if you are certain that
% the underlying rtiostream implementation does not contain
% errors or bugs and you want to do a 3D plot of the
% performance. This option exists because saving the incoming
% data has an impact onto the generated 3D plot at large
% link speeds and low pc/target sizes.

% Available parameters defined here
properties (Constant)
param_pcSize = coder.rtiostreamtest.BandwidthOutgoingTest.param_pcSize;
param_targetSize = coder.rtiostreamtest.BandwidthOutgoingTest.param_targetSize;
param_size = coder.rtiostreamtest.BandwidthOutgoingTest.param_size;
param_skipCheck = 'skipCheck';

default_pcSize = 1; % 1 chunk at a time
default_targetSize = 1; % 1 chunk at a time
default_size = 100; % 100 chunks
default_skipCheck = false; % Check for data integrity
end

methods (Static)

function [pcSize, targetSize, size, skipCheck] = getParameters(parameters)
% GETPARAMETERS parse parameters into local variables

import coder.rtiostreamtest.*;

pcSize = Test.getSetting(parameters, BandwidthIncomingTest.param_pcSize, BandwidthIncomingTest.default_pcSize);
targetSize = Test.getSetting(parameters, BandwidthIncomingTest.param_targetSize, BandwidthIncomingTest.default_targetSize);
size = uint32(Test.getSetting(parameters, BandwidthIncomingTest.param_size, BandwidthIncomingTest.default_size));
skipCheck = Test.getSetting(parameters, BandwidthIncomingTest.param_skipCheck, BandwidthIncomingTest.default_skipCheck);
end

end

methods

function this = BandwidthIncomingTest(name)
if nargin == 0, name = 'BandwidthIncomingTest.m'; end;
this = this@coder.rtiostreamtest.Test(name);
end

function processThroughput = runTest(~, connection, parameters)
% PROCESSTHROUGHPUT is in B/s
% dimensions

try
%% Initialization
[pcSize, targetSize, size, skipCheck] = coder.rtiostreamtest.BandwidthIncomingTest.getParameters(parameters);

dataReceived = 0;

if targetSize > connection.targetBufferSize
coder.rtiostreamtest.Test.warning('WarningIncomingSubtestsSkipped', ...
targetSize, connection.targetBufferSize);
processThroughput = 0;
return;
end

% Initialize container for storing incoming data
if ~skipCheck
dataToReceive = zeros(1, size);
end

% Build the macro
connection.sendCommandAndAck(...
connection.op_macro_repeat_start);

connection.sendCommandAndAck(...
connection.op_macro_blockSendFast, targetSize);

connection.sendCommandAndAck( ...
connection.op_macro_repeat, ...
idivide(size, targetSize));

% If data does not exactly divide
remainder = mod(size, targetSize);
if remainder ~= 0
connection.sendCommandAndAck( ...
connection.op_macro_blockSendFast, remainder);
end

%% Time critical section

processTic = tic;

% Start macro
connection.sendCommand(connection.op_macro_run);

% Send data
for k = 1 : pcSize : size

% Make sure we don't try to receive more than we need
last = k + pcSize - 1;
if last > size
last = size;
end

dataReceived = dataReceived + last - k + 1;

% Receive from target
if skipCheck
connection.blockingRecv(double(last - k + 1));
else
data = connection.blockingRecv( ...
double(last - k + 1));
dataToReceive(k : last) = data;
end
end

% Wait for confirmation that the test was successful
connection.waitForAck;

elapsed = toc(processTic);

% Calculate value
processThroughput = double(size * connection.memUnitSize) / elapsed;

% Check incoming data for integrity
if ~skipCheck
[errPos, errMsg] = ...
coder.rtiostreamtest.ServerConnection.checkFastData(...
dataToReceive);

if errPos ~= -1
coder.rtiostreamtest.Test.error('IncomingError', errMsg);
end
end

catch origException
% add generic message
[errMsg, errId] = DAStudio.message('Connectivity:RtIOStreamTest:InfoIncomingError', ...
pcSize, targetSize, dataReceived, size);
exception = MException(errId, '%s', errMsg);
exception = exception.addCause(origException);
throw(exception);
end
end

end
end