classdef StreamingData < rtw.pil.CodeInfoData
% STREAMINGDATA is a generic data to be transferred between host and target
%(e.g., signal and state logging)

% Copyright 2019 The MathWorks, Inc.

methods
function this = StreamingData(codeInfoDataInterface, ...
codeInfoDataInterfaceIdx, ...
clientInterface, ...
codeInfoUtils, ...
codeInfoType)
this@rtw.pil.CodeInfoData(codeInfoDataInterface, ...
codeInfoType, ...
codeInfoDataInterfaceIdx, ...
clientInterface, ...
codeInfoUtils);
end

% write assignments from the target variable to the data transfer variable
function writeOutputAssignment(this, dataElement, writer, targetInterface)
if ~dataElement.isGetSetViaPointer
% bitfields are not addressable and will not be supported by
% this approach; we should check how the C API handles
% these, but once we need to (once we support custom storage
% classes), maybe we will be able to use the (global) expression to
% handle bitfields
assert(~this.isBitFieldMember, 'Bitfields not supported: cannot use address.');
% get assignment data info
[dataType, identifier] = this.getAssignmentDataInfo(dataElement);
% open any required loops
dataElement.writeStructArrayHeader(writer);
writer.wBlockStart('');
this.writeAddress(dataElement, writer, targetInterface);
% get storage info
storageSize = dataElement.getNumElements;
targetBaseTypeIdentifier = this.getTargetBaseTypeIdentifier(dataElement);
for index = 0:storageSize - 1
dataExpression = dataElement.getAssignmentDataElementExpression(identifier, index);
% add the offset to the base address
indexStr = int2str(index);
expression = ['(((' targetBaseTypeIdentifier '*) dataAddress)[' indexStr '])'];
writer.writeLine([dataExpression ' = (' dataType ') ' expression ';']);
end
writer.wBlockEnd;
% close any required loops
dataElement.writeStructArrayTrailer(writer);
end
end
end

methods(Sealed)
function checksum = getChecksum(LoggingDataInstances)
checksum = CGXE.Utils.md5([]);
% support array of LoggingData objects
for loggingDataIdx = 1:length(LoggingDataInstances)
loggingData = LoggingDataInstances(loggingDataIdx);
checksum = loggingData.getChecksumItem(checksum);
end
end
end

methods (Abstract, Access = public)
checksum = getChecksumItem(dataInstance, checksum);
decimation = getDecimation(this);
maxPoints = getMaxPoints(this);
blockPath = getEscapedBlockPath(this);
portIdx = getPortIdx(this);
propSigName = getPropagatedName(this);
timeSeriesName = getEscapedTimeSeriesName(this);
sid = getEscapedTimerSeriesSID(this);
loggingName = getEscapedLoggingName(this);
type = getType(this);
type = getHostType(this);
domain = getDomain(this);
end

methods (Static, Access = 'protected')

function isConst = isConstantReference(dataInterface)
% return true if the dataInterface refers to a variable which is
% part of a constant reference. This happens only with C++ class
% and it is indepedent from internal visibility
isConst = false;
impl = dataInterface.Implementation;
while(true)
if isa(impl, 'coder.descriptor.ClassMethodExpression')
isConst = true;
break;
end
if ~isprop(impl, 'BaseRegion')
break;
end
impl = impl.BaseRegion;
end
end

function escapedString = escapeString(inputString)
% escape input string for use as a C string
%
% escape \'s, e.g. \ -> \\, \n -> \\n
escapedString = strrep(inputString, '\', '\\');
% replace newline chars with "\n"
escapedString = strrep(escapedString, newline, '\n');
% escape "'s
escapedString = strrep(escapedString, '"', '\"');
end
end
end