www.gusucode.com > robotsimulink 工具箱 matlab源码程序 > robotsimulink/robotslros/+robotics/+slros/+internal/+bus/Util.m

    classdef Util
    %This class is for internal use only. It may be removed in the future.
    
    %BUS.UTIL - Utility functions for working with Simulink buses
    
    %   Copyright 2014-2016 The MathWorks, Inc.
    
    properties(Constant)
        BusNamePrefix = 'SL_Bus_'
        VarlengthInfoBusName = 'SL_Bus_ROSVariableLengthArrayInfo'
    end
    
    %% Utility functions related to variable-length arrays
    methods (Static)

        function [datatype,busName] = varlenInfoBusDataTypeStr()
            busName = robotics.slros.internal.bus.Util.VarlengthInfoBusName;
            datatype = ['Bus: ' busName];
        end
        
        
        function s = getVarlenInfoStruct(curlen, recvdlen)
            s.CurrentLength = uint32(curlen);
            s.ReceivedLength = uint32(recvdlen);
        end
        
        
        function createVarlenInfoBusIfNeeded()
            busName = robotics.slros.internal.bus.Util.VarlengthInfoBusName;
            busExists = ~isempty(evalin('base', ['whos(''' busName ''')']));
            if ~busExists                
                elems(1) = Simulink.BusElement;
                elems(1).Name = 'CurrentLength';
                elems(1).Dimensions = 1;
                elems(1).DimensionsMode = 'Fixed';
                elems(1).DataType = 'uint32';
                elems(1).Complexity = 'real';
                elems(1).SamplingMode = 'Sample based';
                elems(1).Description = '';
                
                elems(2) = Simulink.BusElement;
                elems(2).Name = 'ReceivedLength';
                elems(2).Dimensions = 1;
                elems(2).DimensionsMode = 'Fixed';
                elems(2).DataType = 'uint32';
                elems(2).Complexity = 'real';
                elems(2).SamplingMode = 'Sample based';
                elems(2).Description = '';
                
                bus = Simulink.Bus;
                bus.Description = '';
                bus.Elements = elems;
                assignin('base', busName, bus);
            end
        end

        
        function infostruct = getArrayInfoStructMetadata()
            infostruct.PropertySuffix = '_SL_Info';
            infostruct.CurLengthProp = 'CurrentLength';
            infostruct.RcvdLengthProp = 'ReceivedLength';            
            infostruct.LengthTypeSL = 'uint32';
            infostruct.LengthTypeCpp = 'uint32_T';  
        end

        
        function arrayInfoElemName = getArrayInfoElementName(arrayElemName)
            infostruct = robotics.slros.internal.bus.Util.getArrayInfoStructMetadata();
            arrayInfoElemName = [arrayElemName infostruct.PropertySuffix];            
        end        
    end

    
    %%  Utility functions for handling std_msgs/Empty
    methods (Static)
       
        function name = getDummyElementNameForStdEmptyMsg()
            name = 'SL_DummyData';
        end

        
        function elem = getDummyElementForStdEmptyMsg()
            elem = Simulink.BusElement;
            elem.Name = robotics.slros.internal.bus.Util.getDummyElementNameForStdEmptyMsg;
            elem.Dimensions = 1;
            elem.DimensionsMode = 'Fixed';
            elem.DataType = 'boolean';
            elem.Complexity = 'real';
            elem.SamplingMode = 'Sample based';
            elem.Description = '';            
        end        
        
    end
    
    %%  General Bus-related utilities
    methods (Static)
        function allMsgsMap = getAllMessageInfoMapForModel(model)
            validateattributes(model, {'char'}, {'nonempty'});
            topLevelMsgTypes = robotics.slros.internal.bus.Util.getBlockLevelMessageTypesInModel(model);
            allMsgsMap = containers.Map;
            for i=1:numel(topLevelMsgTypes)
                map = robotics.slros.internal.sim.createROSMsgInfoMap(struct(...
                    'MessageType', topLevelMsgTypes{i}, ...
                    'ModelName', model, ...
                    'MapKeyType', 'msgtype', ...
                    'Recurse', true));
                requiredMsgs = keys(map);
                for j=1:numel(requiredMsgs)
                    if ~isKey(allMsgsMap, requiredMsgs{j})
                        allMsgsMap(requiredMsgs{j}) = map(requiredMsgs{j});
                    end
                end
            end
        end

        
        function msgTypes = getBlockLevelMessageTypesInModel(model)
            validateattributes(model, {'char'}, {'nonempty'});
            [~, ~, blockMsgTypes] = robotics.slros.internal.bus.Util.getROSBlocksInModel(model);
            msgTypes = unique( blockMsgTypes  );
        end

        
        function [blockList, paramBlockList, blockMsgTypes] = getROSBlocksInModel(model)
            validateattributes(model, {'char'}, {'nonempty'});            
            lbdata = libinfo(bdroot(model), ...
                'LookUnderMasks', 'all', ...
                'Regexp', 'on', ...
                'MaskType', 'ROS (Publish|Subscribe|Blank Message)');            
            blockList = {lbdata(:).Block};
            blockList = blockList(:);
            if nargout > 2
                blockMsgTypes = get_param(blockList,'messageType');
            end
            
            % Find Parameter Blocks
            lbdata = libinfo(bdroot(model), ...
                'LookUnderMasks', 'all', ...
                'Regexp', 'on', ...
                'MaskType', 'ROS (Set Parameter|Get Parameter)');
            paramBlockList = {lbdata(:).Block};
            paramBlockList = paramBlockList(:);
        end
        
        
        function clearSLBusesInBaseWorkspace()
            evalin('base', ['clear ' robotics.slros.internal.bus.Util.BusNamePrefix '*']);
        end
      
        
        function bus = getBusObjectFromBusName(busName)
            bus = evalin('base', busName);
        end
                
        
        function [bus,busName] = getBusObjectFromMsgType(rosMsgType, model)
            busName = robotics.slros.internal.bus.Util.createBusIfNeeded(rosMsgType, model);
            bus = evalin('base', busName);
        end
        
        
        function busname = getBusNameFromDataTypeStr(dataTypeStr)
            matches = regexp(dataTypeStr, 'Bus:[ ]\s*(.*)', 'tokens');
            if ~isempty(matches)
                busname = matches{1}{1};
            else
                busname = '';
            end
        end
        
        
        function [busExists,busName] = checkForBus(rosMsgType, model)
            busName = robotics.slros.internal.bus.Util.rosMsgTypeToBusName(rosMsgType, model);
            busExists = ~isempty(evalin('base', ['whos(''' busName ''')']));
        end

        
        function busName = createBusIfNeeded(rosMsgType, model)
            validateattributes(rosMsgType, {'char'}, {'nonempty'});
            validateattributes(model, {'char'}, {});
            
            [busExists,busName] = robotics.slros.internal.bus.Util.checkForBus(rosMsgType, model);
            if busExists
                return;
            end            
            
            % If message class does not exist, rosmessage will error
            % (robotics:ros:message:NoMatlabClass).
            emptyRosMsg = rosmessage(rosMsgType); % create an empty rosmessage
            
            robotics.slros.internal.bus.createBusDefnInBaseWorkspace(emptyRosMsg, model);
        end
                
        
        %%
        function [datatype, busName, msgType] = rosTimeToDataTypeStr(rosClassName, model)
            msgType = robotics.slros.internal.bus.Util.rosTimeToQuasiMsgType(rosClassName);
            [datatype, busName] = robotics.slros.internal.bus.Util.rosMsgTypeToDataTypeStr(msgType, model);
        end
                
        
        function quasiMsgType = rosTimeToQuasiMsgType(rosClassName)
            entity = robotics.slros.internal.ROSUtil.getTimeEntityType(rosClassName);
            if ~isempty(entity)
                quasiMsgType = ['ros_time/' entity]; % can be Time or Duration
            else
                assert(false, 'Unexpected classname: %s', rosClassName);
            end        
        end
        
        
        %%
        function [datatype,busName] = rosMsgTypeToDataTypeStr(rosMsgType, model)
            % This is used wherever a Simulink DataTypeStr is required
            % (e.g., for specifying the output datatype of a Constant block)
            % ** DOES NOT CREATE A BUS **
            busName = robotics.slros.internal.bus.Util.rosMsgTypeToBusName(rosMsgType, model);
            datatype = ['Bus: ' busName];
        end
                   
        
        function busName = rosMsgTypeToBusName(rosMsgType, model)
            %
            % rosMsgTypeToBusName(MSGTYPE,MODEL) returns the bus name
            % corresponding to a ROS message type MSGTYPE (e.g.,
            % 'std_msgs/Int32') and a Simulink model MODEL. The function
            % uses the following rules:
            % 
            % Rule 1 - Generate a name using the format:
            %    SL_Bus_<modelname>_<msgtype>
            %
            % Rule 2 - If the result of Rule 1 is longer than 60
            % characters, use the following general format: 
            %    SL_Bus_<modelname(1:25)>_<msgtype(end-25:end)>_<hash>
            % where <hash> is a base 36 hash of the full name (output of
            % rule #1). 
            %
            % ** THIS FUNCTION DOES NOT CREATE A BUS OBJECT **
            
            validateattributes(rosMsgType, {'char'}, {'nonempty'});
            assert(ischar(model));
            
            if isempty(model)
                modelnameSuffix = '';
            else
                modelnameSuffix = '_';
            end
            
            maxlen = 60; choplen=25;
            assert(maxlen <= namelengthmax);
            
            busName = [robotics.slros.internal.bus.Util.BusNamePrefix ...
                       model modelnameSuffix rosMsgType];                        
            if length(busName) < maxlen
                busName = matlab.lang.makeValidName(busName, 'ReplacementStyle', 'underscore');                
            else 
                % add a trailing hash string (5-6 chars) to make the busname unique 
                hashStr = robotics.slros.internal.bus.Util.hashString(busName);
                
                idx = strfind(rosMsgType, '/');
                if isempty(idx)
                    idx = 0;
                else
                    idx = idx(1);
                end
                model = model(1:min(end,choplen));  % get first 25 chars
                rosMsgType = rosMsgType(idx+1:min(idx+choplen,end));  % get first 25 chars
                busName = matlab.lang.makeValidName(...
                    [robotics.slros.internal.bus.Util.BusNamePrefix ...
                     model modelnameSuffix rosMsgType '_' hashStr], ...
                    'ReplacementStyle', 'underscore');
            end
        end
                        
    end

    
    methods(Static, Access=private)
        
        function hashStr = hashString(str)
            javaStr = java.lang.String(str);
            hashStr = lower(dec2base(uint64(abs(javaStr.hashCode)), 36)); % usually 5-6 chars
        end
 
        
    end
        
end