classdef (Sealed) PILCommunication
% PILCOMMUNICATION Class of static helper functions used for pil communication logic.
%
% This is an undocumented class. Its methods and properties are likely to
% change without warning from one release to the next.

% Copyright 2020-2022 The MathWorks, Inc.

methods (Static)
function isTypeSupported = getIsTypeSupportedFroPIL(dataTypeService, matlabTypeString)

integer = false;

switch (matlabTypeString)
case {'double'}
isTypeSupported = dataTypeService.getIsTypeSupported('Double');
case {'single'}
isTypeSupported = dataTypeService.getIsTypeSupported('Float');
case {'half'}
isTypeSupported = dataTypeService.getIsTypeSupported('Half');
case {'boolean' 'bool' 'logical' 'char'}
integer = true;
integerSize = dataTypeService.getTypeSize('Char');
case {'int8' 'uint8' 'int16' 'uint16' 'int32' 'uint32' 'int64' 'uint64'}
integer = true;
integerSize = str2double(cell2mat(regexp(matlabTypeString, 'u?int(\d+)', 'once', 'tokens')));
end

if (integer)
wordSize = dataTypeService.getWordSize();
if (dataTypeService.getIsByteAddressable() || ...
~dataTypeService.getIsByteAddressable() && integerSize >= wordSize)
isTypeSupported = dataTypeService.getIsIntegerSizeSupported(integerSize);
else
% PIL can still support word addressable types if
% the size is smaller than the native word size
% but smallest integer is not smaller than the
% native word size - by up casting.
smallestIntSize = dataTypeService.getSmallestSupportedIntegerSize();
isTypeSupported = smallestIntSize >= wordSize;
end
end
end

% parse the output file for the server port number
function [serverPort, outputFileContents] = parseOutputFileForHostServerPort(exePID, ...
outputFile, ...
extendTimeout)
if nargin < 3
extendTimeout = false;
end

if extendTimeout
% G1877705: rsim executables can take a long time to start
% therefore the number of retries with diagnostic
% info being printed is extended to 12 (x 15s)
numRetriesWithDiagnosticInfo = 12;
else
% default is 3 (x 15s) extended retries with diagnostic
% info being printed
numRetriesWithDiagnosticInfo = 3;
end

nRetry=50;
while nRetry > 0
% check for file existence before calling fileread
outputFileExists = exist(outputFile, 'file');
if outputFileExists
% found output file
break;
end
% pause then try again
pause(0.1);
nRetry = nRetry - 1;
end
if ~outputFileExists
rtw.connectivity.ProductInfo.error('target', 'MissingOutputFile', ...
outputFile);
end

% read server portNumber with 15 seconds timeout
[portCell, outputFileContents] = coder.connectivity.PILCommunication.readServerPortNumber(outputFile);

% timeout extension to fix g1465058
if isempty(portCell)
retry = 0;
% extend timeout in multiples of 15s, printing diagnostic
% info for each iteration
while isempty(portCell) && retry < numRetriesWithDiagnosticInfo
% print diagnostics and retry
coder.connectivity.PILCommunication.printDiagnosticInfo(...
outputFileContents, outputFile, exePID, retry);
[portCell, outputFileContents] = ...
coder.connectivity.PILCommunication.readServerPortNumber(outputFile);
retry = retry +1;
end
end

serverPort = '';
if ~isempty(portCell)
serverPort = portCell{1};
end
end

function serverPort = pollForServerPortNumber(appExecutionManager, extendTimeout)
arguments
appExecutionManager
extendTimeout = false;
end
if extendTimeout
% G1877705: rsim executables can take a long time to start
% therefore extend the timeout to 3 minutes. See also
% ext_util.m
nRetry = 1800;
else
% Set polling to 1 minute to avoid sporadic failures (g2668758).
nRetry=600;
end

% increase the time out for maca64 platform for sporadic
% failures (g3002927), to be reconsidered when g3082691 is addressed
if isequal(computer('arch'), 'maca64')
nRetry = nRetry*6;
end

portCell = {};
while nRetry > 0
appStdOut = appExecutionManager.getStandardOutput();
portCell = regexp(appStdOut, ...
'Server Port Number: (\d*)[\n|\r]', 'tokens', 'once');
if ~isempty(portCell)
% found server port number
break;
end
% Pause then try again
pause(0.1);
nRetry = nRetry - 1;
end

serverPort = '';
if ~isempty(portCell)
serverPort = portCell{1};
end
end

function [portCell, outputFileContents] = readServerPortNumber(outputFile)
% The timeout as been extended to 15s as a fix for g1152712.
% Using 32bit MATLAB on win64 there is a significant delay
% between the call to a win32 app and the beginning of its execution.
nRetry=150;

while nRetry > 0
outputFileContents = fileread(outputFile);
portCell = regexp(outputFileContents, ...
'Server Port Number: (\d*)', 'tokens', 'once');
if ~isempty(portCell)
% found server port number
break;
end
% Pause then try again
pause(0.1);
nRetry = nRetry - 1;
end
end

function printDiagnosticInfo(outputFileContents, outputFile, exePID, nRetry)
% construct commands:
% ls - print outputFile file attributes and time of last change
% top - execute only once and show exePID information including its status
% du - print tempDir contents size and total size
% df - print disk size and use percentage

retryMsgID = sprintf('UnknownServerPort_Diagnostics - %d', nRetry);
if isunix
% get the temp dir used by tempname
tempDir = tempdir;
switch computer
case 'GLNXA64'
lsCommand = sprintf('ls -al --full-time "%s"', outputFile);
topCommand = sprintf('top -b -n1 -c -s -p %d', exePID);
duCommand = sprintf('du -ch "%s"', tempDir);
dfCommand = sprintf('df -H --total "%s"', tempDir);
case {'MACI64', 'MACA64'}
lsCommand = sprintf('ls -al "%s"', outputFile);
topCommand = sprintf('top -l1 -pid %d', exePID);
duCommand = sprintf('du -ch "%s"', tempDir);
dfCommand = sprintf('df -H "%s"', tempDir);
otherwise
assert(false, 'Unexpected host platform.');
end
% run commands and display output
[~, fileInfo] = system(lsCommand);
[~, processInfo] = system(topCommand);

fprintf('%s\nProcessInfo: %s\nFile content is: %s\nFile attributes are: %sTime is %s\n',...
retryMsgID, processInfo, outputFileContents, fileInfo, datestr(now));
if nRetry >= 2
[~, duCommandInfo] = system(duCommand);
[~, dfCommandInfo] = system(dfCommand);
fprintf('UnknownServerPort_Diagnostics - tempDir status\n');
fprintf('tempDir contents and usage:\n%s\ndisk usage:\n%s\n',...
duCommandInfo, dfCommandInfo);
end
else
fprintf('%s\n', retryMsgID);
end
end
end
end