function helperStartReceiver(algorithmMode)
% helperStartReceiver Executes the data reception and processing example.
%
% Receive live data stream via CAN FD & TCP/IP. The client receives live 
% video stream via TCP/IP and sensor data (radar, vision, lane object lists
% and IMU) via CAN FD from the transmitter. The received live data stream 
% is processed and fed into Forward Warning Collision algorithm using Sensor 
% Fusion. The algorithm was implemented by MATLAB code. MATLAB Coder 
% generates C/C++ code from MATLAB code. The generated C code has been 
% compiled into a function that MATLAB can call with Software-In-the-Loop mode.
%
% This example uses multiple toolboxes:
%   1) Automated Driving Toolbox for visualization, FCW algorithm
%   2) Vehicle Network Toolbox for CAN FD
%   3) Instrument Control Toolbox for TCP/IP
%
% Copyright 2017-2018 The MathWorks, Inc.

% Default states of unprovided inputs.
if nargin < 1
    algorithmMode = 'interpreted';
end

% Validate the mode input which controls how the example runs.
if ~any(strcmpi(algorithmMode, {'interpreted','mex','sil'}))
    error('Mode must be ''interpreted'', ''mex'', or ''sil''');
end

% Ensure proper components are available to run specific modes.
switch algorithmMode
    case 'mex' % MEX (MATLAB Coder)
        if ~exist('trackingForFCW_kernel_mex','file')
            error(['Cannot find trackingForFCW_kernel_mex. ', ...
                'To generate it run: helperGenerateCode(''mex'')']);
        end
    case 'sil' % Software-In-the-Loop (SIL) (Embedded Coder)
        if ~exist('trackingForFCW_kernel_sil','file')
            error(['Cannot find trackingForFCW_kernel_sil. ', ...
                'To generate it run: helperGenerateCode(''sil'')']);
        end
end

% Prepare to construct the figure.
figNameRoot = 'Forward Collision Warning using SensorFusion by Live Data Stream';       

% If figure already exists, alert to close it.
figureHandle = findobj('Type','Figure','Tag',figNameRoot);
if ~isempty(figureHandle)
    warning(['Figure ''' figNameRoot ''' is already open. ' ...
        'Please close the figure before calling this command.']);
    return
end

% Create the new figure.
hFigure = figure('Name',figNameRoot, ...
    'CloseRequestFcn',@figCloseReqest, ...
    'NumberTitle','off', ...
    'MenuBar','none', ...
    'Tag',figNameRoot);
scrsz = double(get(groot,'ScreenSize'));
hFigure.Position = [scrsz(3)*0.07 scrsz(4)*0.1 scrsz(3)*0.65 scrsz(4)*0.6];

% Create uipanel and axes for video, bird's-eye plot, button, listbox. 
hPanel1 = uipanel(hFigure,'Units','Normalized','Position',[0   0 1/2 4/5],'Title','Video');
hPanel2 = uipanel(hFigure,'Units','Normalized','Position',[1/2 0 1/2 1],'Title','Birds-Eye Plot');
hPanel3 = uipanel(hFigure,'Units','Normalized','Position',[0 4/5 1/2 1/5],'Title','','BorderType','none');
hVideoAxes = axes('Parent',hPanel1,'Position',[0.01 0.01 0.98 0.98],'Visible','off');
hBepAxes   = axes('Parent',hPanel2,'Position',[0.1 0.1 0.88 0.88]);

% Create listbox for displaying message.
ui.msg_list = uicontrol('Style','listbox', ...
    'String','',...
    'Parent',hPanel3,...
    'Units','Normalized',...
    'FontSize',10,...
    'Position',[0.21 0.05 0.78 0.9]);

% Create pushbutton for start receiving live data stream.
ui.start_pushbutton = uicontrol('Style','pushbutton', ...
    'String','START',...
    'Parent',hPanel3,...
    'FontSize',12,...
    'FontWeight','bold',...
    'Units','Normalized',...
    'Position',[0.01 0.67 0.19 0.28],...
    'Callback', @StartUpdate);

% Create pushbutton for stop receiving live data stream.
ui.stop_pushbutton = uicontrol('Style','pushbutton', ...
    'String','STOP',...
    'Parent',hPanel3,...
    'FontSize',12,...
    'FontWeight','bold',...
    'Units','Normalized',...
    'Position',[0.01 0.36 0.19 0.28],...
    'Callback', @StopUpdate);

% Create editbox for displaying frame counter.
ui.step_edit = uicontrol('Style','edit', ...
    'String','0',...
    'Parent',hPanel3,...
    'FontSize',12,...
    'FontWeight','bold',...
    'Units','Normalized',...
    'Position',[0.01 0.05 0.19 0.28]);

% Set default button states.
set(ui.start_pushbutton,'Enable','off');
set(ui.stop_pushbutton,'Enable','off');

% Initialize variables.
statusMsg = '';
showStatusMsgs('>> Initializing App ...');

StopRequest = false;
CloseRequest = false;

WarnWave = sin(1:.6:200);
beepSound = audioplayer(WarnWave, 10000);

% Configure Bird's-Eye Plot.
sensorConfigurationFile = 'SensorConfigurationData.mat';
axisLimits = [0,100; -30,30];
bepPlotters = initializeBirdsEyePlot(hBepAxes,axisLimits,sensorConfigurationFile);

% Load the monoCamera object for on-video display.
monoCam = load('FCWDemoMonoCameraSensor.mat');

% Set video size.
frameHeight = 480;
frameWidth = 640;
frameSize = (frameHeight * frameWidth * 3);
vFrame = ones(frameHeight, frameWidth, 3, 'uint8')*uint8(128);
videoDisplayHandle = imshow(vFrame,'Parent',hVideoAxes);

% Open the CAN FD DBC file.
canDb = canDatabase('VNT_ADST.dbc');

% Configure CAN FD receive channel.
% Note to enable the example for physical hardware and using multiple
% computers, change the lines below to target canChannel to the desired
% device and adjust bus speed as needed.
CANchann = canChannel('Vector','Virtual 1',2,'ProtocolMode','CAN FD');
configBusSpeed(CANchann,1e6,2,6,3,8e6,2,6,3);
CANchann.Database = canDb;

% Set CAN FD channel online.
start(CANchann);
showStatusMsgs('[CAN FD] Channel is online ...');

% Set TCP/IP address and port for local machine communication.
% Note to enable the example for physical hardware and using multiple
% computers, set the IP address of the transmitting maching to 192.168.1.2
% and enter that value as the TCP/IP address below.
tcpipAddr = '127.0.0.1';
tcpipPort = 2112;

% Configure the TCP/IP connection. Terminator has to be defined to avoid
% any communication delay.
tcpipObj = tcpip(tcpipAddr, tcpipPort, 'NetworkRole','client','InputBufferSize',frameSize*10);
tcpipObj.Terminator = '';

% Try to connect to the transmitter.
showStatusMsgs(sprintf('[TCP/IP] Trying to connected to localhost (%s:%d)', ...
    tcpipObj.RemoteHost, tcpipObj.RemotePort));

while strcmp(tcpipObj.Status,'closed')
    try
        fopen(tcpipObj);
        showStatusMsgs(sprintf('[TCP/IP] Connected to localhost (%s:%d)', ...
            tcpipObj.RemoteHost, tcpipObj.RemotePort));
    catch
        % Pause to provide opportunity for Ctrl+C.
        pause(1);
        
        % If user closes figure while waiting to connect, the tcpipObj is
        % invalid, so return
        if ~tcpipObj.isvalid
            return
        end
    end
end
                    
% Prepare UI for start condition.
set(ui.start_pushbutton,'Enable','on');
showStatusMsgs('>> Press START to receive data from server ...');

% An initial ego lane is calculated. If the recorded lane information is
% invalid, define the lane boundaries as straight lines half a lane
% distance on each side of the car.
laneWidth = 3.6; % meters
egoLane = struct('left', [0 0 laneWidth/2], 'right', [0 0 -laneWidth/2]);

% Set an update time.
timeStep = 0.05;

% Define the position and velocity selectors:
% The state vector is in constant acceleration: [x;vx;ax;y;vy;ay]
% Constant acceleration position: [x;y] = [1 0 0 0 0 0; 0 0 0 1 0 0] * State
positionSelector = [1 0 0 0 0 0; 0 0 0 1 0 0];
% Constant acceleration velocity: [x;y] = [0 1 0 0 0 0; 0 0 0 0 1 0] * State
velocitySelector = [0 1 0 0 0 0; 0 0 0 0 1 0];

vTitle = title(hVideoAxes,'');
vTitle.FontWeight = 'normal';

tElapsed = repmat( struct(...
    'RcvCAN',   single(0),...  
    'RcvVideo', single(0),...     
    'FCW',      single(0),...
    'Display',  single(0),...
    'Total',    single(0)),...
    [204 1]);

% Set previous step to inf to ensure resetting states.
previousStep = inf;
set(ui.start_pushbutton,'Enable','off');
set(ui.stop_pushbutton,'Enable','on');
play(beepSound);
showStatusMsgs('>> Now, receiving data ...');

% Remove data from input buffer of TCP/IP.
flushinput(tcpipObj);

% Clear receiving buffer of CAN FD channel.
discard(CANchann);

% Loop and process until figure is closed.
while ~CloseRequest
    
    % Receive CAN FD messages over CAN FD receive channel.      
    [visionObjects, radarObjects, imu, lanes, cmd, currentStep, vFrame, tElapsedRcv] = dataReceiver( ...
        CANchann, tcpipObj, vFrame, frameSize);
    
    % Check if sensor data was received.
    if cmd == 3
        tStart = tic;
        tElapsed(currentStep).RcvCAN   = tElapsedRcv.CAN;
        tElapsed(currentStep).RcvVideo = tElapsedRcv.Video;
        
        if currentStep <= previousStep
            % If a previous tracker is defined, clear algorithm so time
            % does not appear to go backwards.
            clear trackingForFCW_kernel trackingForFCW_kernel_mex trackingForFCW_kernel_sil
        end
        
        % Update time.
        time = (currentStep-1) * timeStep;
        
        tStartFCW = tic;
        % Get the tracking function depends on the execution mode.
        switch algorithmMode
            case 'mex' % MEX (MATLAB Coder)
                functionHandle = @trackingForFCW_kernel_mex;
            case 'sil' % Software-In-the-Loop (SIL) (Embedded Coder)
                functionHandle = @trackingForFCW_kernel_sil;
            otherwise % Interpreted mode
                functionHandle = @trackingForFCW_kernel;
        end
        
        % Call the FCW algorithm.
        [confirmedTracks, egoLane, ~, mostImportantObject] = functionHandle(...
            visionObjects, radarObjects, imu, lanes, egoLane, time, positionSelector, velocitySelector);
        
        tElapsed(currentStep).FCW = toc(tStartFCW);        
  
        % Figure could be invalid if user closes figure while streaming data.
        if  ~StopRequest && isvalid(hFigure)
            tStartDisplay = tic;
            
            % Display frame counter.
            ui.step_edit.String = num2str(currentStep);
            vTitle.String = sprintf('Algorithm (%s):  %7.3f ms', algorithmMode, tElapsed(currentStep).FCW * 1e3);
            
            % Update video frame with overlay.
            vFrameWithOverlay = updateVideoAnnotations(vFrame,monoCam.sensor,...
                mostImportantObject,confirmedTracks,lanes,positionSelector,true);
            
            % Display video frame with overlay.
            set(videoDisplayHandle, 'CData', vFrameWithOverlay);
            
            % Update bird's-eye plot.
            updateBirdsEyePlot(bepPlotters,mostImportantObject,confirmedTracks,...
                radarObjects,visionObjects,lanes,egoLane,...
                positionSelector,velocitySelector,...
                true,axisLimits);
            
            tElapsed(currentStep).Display = toc(tStartDisplay);
        else
            tElapsed(currentStep).Display = 0;
            pause(1/1000); 
        end
        
        % Update previous step.
        previousStep = currentStep;
        tElapsed(currentStep).Total = toc(tStart) + tElapsed(currentStep).RcvCAN + tElapsed(currentStep).RcvVideo;
    else
        pause(1/1000);
    end
end

% show elapsed time anaysis plot
sample = 1:204;

figure;
zoom off; grid off;
set(gcf,'Numbertitle','off');
set(gcf,'Name','Elapsed time analysis');
hold on;

plot(sample,[tElapsed.RcvCAN] * 1e3,...
    'Color','blue',...
    'LineStyle','-',...
    'LineWidth',0.1,...
    'Marker','o',...
    'MarkerSize',2,...
    'MarkerEdgeColor','blue',...
    'MarkerFaceColor','blue');

plot(sample,[tElapsed.RcvVideo] * 1e3,...
    'Color','cyan',...
    'LineStyle','-',...
    'LineWidth',0.1,...
    'Marker','o',...
    'MarkerSize',2,...
    'MarkerEdgeColor','cyan',...
    'MarkerFaceColor','cyan');

plot(sample,[tElapsed.FCW] * 1e3,...
    'Color','magenta',...
    'LineStyle','-',...
    'LineWidth',0.1,...
    'Marker','o',...
    'MarkerSize',2,...
    'MarkerEdgeColor','magenta',...
    'MarkerFaceColor','magenta');

plot(sample,[tElapsed.Display] * 1e3,...
    'Color','green',...
    'LineStyle','-',...
    'LineWidth',0.1,...
    'Marker','o',...
    'MarkerSize',2,...
    'MarkerEdgeColor','green',...
    'MarkerFaceColor','green');

plot(sample,[tElapsed.Total] * 1e3,...
    'Color','red',...
    'LineStyle','-',...
    'LineWidth',0.1,...
    'Marker','o',...
    'MarkerSize',2,...
    'MarkerEdgeColor','red',...
    'MarkerFaceColor','red');

label{1} = sprintf('Receive CAN   (%5.2f ms)', mean([tElapsed.RcvCAN])*1e3);
label{2} = sprintf('Receive Video (%5.2f ms)', mean([tElapsed.RcvVideo])*1e3);
label{3} = sprintf('FCW Algorithm (%5.2f ms)', mean([tElapsed.FCW])*1e3);
label{4} = sprintf('Display       (%5.2f ms)', mean([tElapsed.Display])*1e3);
label{5} = sprintf('Total         (%5.2f ms)', mean([tElapsed.Total])*1e3);
legend(label,'FontName','Courier New');

tit = sprintf('Elapsed Time Analysis\n(Algorithm mode: %s)', algorithmMode);
title(tit);

xlim([1 length(sample)]);
ylim([0 250]);
xlabel('sample');
ylabel('tElapse (ms)');
grid('on'); zoom('on');

    function StopUpdate(~, ~)
        % StopUpdate Callback function for stop pushbutton.
        
        % Set mode and manage the UI.
        StopRequest = true;
        play(beepSound);
        set(ui.start_pushbutton,'Enable','on');
        set(ui.stop_pushbutton,'Enable','off');
        showStatusMsgs('>> STOP updating data !!');
    end

    function StartUpdate(~, ~)
        % StartUpdate Callback function for start pushbutton.
        
        % Set mode and manage the UI.
        StopRequest = false;
        play(beepSound);
        set(ui.start_pushbutton,'Enable','off');
        set(ui.stop_pushbutton,'Enable','on');
        showStatusMsgs('>> START updating data !!');
    end

    function showStatusMsgs(msg)
        % showStatusMsgs Display message in the listbox.
        
        i = length(statusMsg)+1;
        statusMsg{i} = msg;
        set(ui.msg_list,'String',statusMsg,'Value',i);
        drawnow;
    end

    function figCloseReqest(~,~)
    % figCloseReqest Execute the figure closeure.

        CloseRequest = true;      
        showStatusMsgs('>> Closing App ...');
        
        if exist('CANchann','var') && ~isempty(CANchann)
            showStatusMsgs('[CAN FD] Channel is offline ...');
            stop(CANchann);
        end
        
        if exist('tcpipObj','var') && ~isempty(tcpipObj)
            showStatusMsgs('[TCP/IP] Disconnecting TCP/IP from the server ...');
            fclose(tcpipObj);
            delete(tcpipObj)
            tcpipObj = [];
        end
        
        delete(hFigure);
        clear trackingForFCW_kernel trackingForFCW_kernel_mex trackingForFCW_kernel_sil;
    end

end
