www.gusucode.com > robotsimulink 工具箱 matlab源码程序 > robotsimulink/robotslros/+robotics/+slros/+internal/+bus/VarlenArraySizeStore.m
classdef VarlenArraySizeStore < handle %This class is for internal use only. It may be removed in the future. % VarlenArraySizeStore is an interface for managing variable-length % array information for a single Simulink model (this information is % stored with the model in the Model Workspace). % % Methods: % updateModel - Update model workspace with modified array-size % info (dirties the model but does not save it) % % getMsgTypeInfo - Get array-size info for a ROS message type % setMsgTypeInfo - Set array-size info for a ROS message type % resetMsgTypeInfo - Clear array-size info for a ROS message type % % getTruncateAction - Get truncate action for the model % setTruncateAction - Set truncate action for the model % % applyMaxLengths - Apply stored array-size limits for a message % (if they exist), else apply defaults % % Static Methods: % getDefaultTruncateAction - Get default truncate action % applyDefaultMaxLengths - Apply default array-size limits to a % message % % See also: bus.VarLenArrayInfo % Copyright 2014 The MathWorks, Inc. properties(Constant) DefaultPrimitiveArrayMaxLen = 128 DefaultMessageArrayMaxLen = 16 end properties(Constant, Access=private) WorkspaceVarName = 'SL_ROS_VariableLengthArrays_MaxSizes' end properties(SetAccess=private) ModelWorkspace DataIsModified = false ModelWSListener ModelName MsgTypeMap CommonInfo end methods function obj = VarlenArraySizeStore(model) % No point in constructing without a model % we would have to keep checking for validity of Map validateattributes(model, {'char'}, {'nonempty'}); % bdIsLoaded() can error if model is not a properly formatted name % The error message (Simulink:utility:InvalidBlockDiagramName) % is informative, so no need to wrap it if ~bdIsLoaded(model) % We could use load_system, but it's not clear when we % would unload (and there would be no indication to use % that the model is loaded). Cleaner to let the user % manage the load/unload error(message('robotics:robotslros:arraysizestore:UnableToLoadModel', model)); end try obj.ModelWorkspace = get_param(model,'ModelWorkspace'); catch % Model does not have a ModelWorkspace param (most likely % old-style .mdl file). error(message('robotics:robotslros:arraysizestore:SLXFormatRequired', model)); end if isempty(obj.ModelWorkspace) % Most likely, the model is a library. if strcmpi(get_param(bdroot(model), 'BlockDiagramType'), 'library') error(message('robotics:robotslros:arraysizestore:LibraryNotAllowed', model)); else error(message('robotics:robotslros:arraysizestore:UnableToLoadWorkspace', model)); end end obj.ModelName = bdroot(model); obj.ModelWSListener = handle.listener(obj.ModelWorkspace, 'ObjectBeingDestroyed', @(~,~) delete(obj)); obj.loadDataFromWorkspace(); end function updateModel(obj) if ~ishandle(obj.ModelWorkspace) error(message('robotics:robotslros:arraysizestore:ModelNoLongerLoaded', obj.ModelName)); end if obj.DataIsModified obj.saveDataToWorkspace(); % ModelWorkspace.saveToModel() cannot be called if source is % 'Model File'. Just set the dirty bit and let the user decide % whether to save the model or not owningModel = obj.ModelWorkspace.ownerName; set_param(owningModel,'Dirty','on'); % Clear the workspace bus variables (so that % subsequent simulation runs get updated sizes) robotics.slros.internal.bus.Util.clearSLBusesInBaseWorkspace(); end end function arrayinfo = getMsgTypeInfo(obj, msgType) if obj.MsgTypeMap.isKey(msgType) msgtypeInfo = obj.MsgTypeMap(msgType); % resuscitate the VarLenArrayInfo object arrayinfo = robotics.slros.internal.bus.VarLenArrayInfo(msgType); arrayinfo.setPropsStruct(msgtypeInfo); else arrayinfo = []; end end function setMsgTypeInfo(obj, msgType, arrayinfo) validateattributes(msgType, {'char'}, {'nonempty'}); validateattributes(arrayinfo, {'robotics.slros.internal.bus.VarLenArrayInfo'}, {'scalar'}); % Don't store as handle array (this is an internal class, % whereas this information will be saved with model, and can % persist across releases) obj.MsgTypeMap(msgType) = arrayinfo.getPropsStruct(); obj.DataIsModified = true; end function resetMsgTypeInfo(obj, msgType) if obj.MsgTypeMap.isKey(msgType) obj.MsgTypeMap.remove(msgType); obj.DataIsModified = true; end end function out = getTruncateAction(obj) out = obj.CommonInfo.ArrayTruncateAction; end function setTruncateAction(obj, action) validateattributes(action, ... {'robotics.slros.internal.bus.VarLenArrayTruncationAction'}, {'scalar'}); if obj.CommonInfo.ArrayTruncateAction ~= action obj.CommonInfo.ArrayTruncateAction = action; obj.DataIsModified = true; end end function applyMaxLengths(obj, arrayinfo) % applyMaxLengths(ARRAYINFO) applies stored array-size limits % for a message (if they exist) to ARRAYINFO. If there are no stored % limits, it applies default array-size limits. % validateattributes(arrayinfo, {'robotics.slros.internal.bus.VarLenArrayInfo'}, {'scalar'}); msgtype = arrayinfo.MessageType; if obj.MsgTypeMap.isKey(msgtype) % msg is in database, return existing values % doApplyDefaults will be flipped to false only if all % conditions are met doApplyDefaults = true; storedInfo = obj.MsgTypeMap(msgtype); validStoredInfo = isstruct(storedInfo) && ... all(isfield(storedInfo, {'PropertyName', 'DataType', 'MaxLength'})); if validStoredInfo storedNames = {storedInfo.PropertyName}; curNames = {arrayinfo.ArrayProps.PropertyName}; if numel(storedNames) == numel(curNames) && all(strcmpi(storedNames, curNames)) arrayinfo.setFromCellArray('MaxLength', {storedInfo.MaxLength}); doApplyDefaults = false; storedInfoMismatch = false; else % stored property names don't match storedInfoMismatch = true; end else % stored info doesn't look right storedInfoMismatch = true; end else % msg is not in database doApplyDefaults = true; storedInfoMismatch = false; end if storedInfoMismatch obj.resetMsgTypeInfo(msgtype); % remove from store warning(message('robotics:robotslros:arraysizestore:MaxArraySizesReset', ... arrayinfo.MessageType, obj.ModelName)); end if doApplyDefaults || storedInfoMismatch obj.applyDefaultMaxLengths(arrayinfo); end end end %% methods(Access=private) function loadDataFromWorkspace(obj) if ~obj.ModelWorkspace.hasVariable(obj.WorkspaceVarName) applyDefaults = true; else try data = obj.ModelWorkspace.getVariable(obj.WorkspaceVarName); obj.CommonInfo = data.CommonInfo; % convert from string to enum type obj.CommonInfo.ArrayTruncateAction = ... robotics.slros.internal.bus.VarLenArrayTruncationAction.fromChar(data.CommonInfo.ArrayTruncateAction); obj.MsgTypeMap = data.MsgTypeMap; applyDefaults = false; catch warning(message('robotics:robotslros:arraysizestore:CorruptedModelWorkspace', ... obj.ModelName)); applyDefaults = true; obj.DataIsModified = true; % Clear workspace bus variables to flush out existing information robotics.slros.internal.bus.Util.clearSLBusesInBaseWorkspace(); end end if applyDefaults obj.CommonInfo = struct(); obj.CommonInfo.ArrayTruncateAction = obj.getDefaultTruncateAction(); obj.MsgTypeMap = containers.Map; end end function saveDataToWorkspace(obj) commonInfo = obj.CommonInfo; commonInfo.ArrayTruncateAction = char(commonInfo.ArrayTruncateAction); data = struct('CommonInfo', commonInfo, 'MsgTypeMap', obj.MsgTypeMap); obj.ModelWorkspace.assignin(obj.WorkspaceVarName, data); end end %% methods(Static) function out = getDefaultTruncateAction() out = robotics.slros.internal.bus.VarLenArrayTruncationAction.EmitWarning; end function applyDefaultMaxLengths(arrayinfo) import robotics.slros.internal.bus.VarlenArraySizeStore validateattributes(arrayinfo, {'robotics.slros.internal.bus.VarLenArrayInfo'}, {'scalar'}); maxLengths = cell(1,numel(arrayinfo.ArrayProps)); for i=1:numel(arrayinfo.ArrayProps) % datatype is either a ROS message type (e.g., % 'geometry_msgs/Point') or a primitive Simulink datatype % (e.g, 'uint8', 'single'). datatype = arrayinfo.ArrayProps(i).DataType; if strfind(datatype,'/') % Array of ROS messages maxLength = VarlenArraySizeStore.DefaultMessageArrayMaxLen; else % Array of primitive type % Note: strings are mapped to arrays of uint8 maxLength = VarlenArraySizeStore.DefaultPrimitiveArrayMaxLen; end maxLengths{i} = maxLength; end arrayinfo.setFromCellArray('MaxLength', maxLengths); end end end