gusucode.com > vnt工具箱matlab源码程序 > vnt/vnt/+vnt/+internal/+mixin/+message/SignalAccess.m

    classdef (Abstract) SignalAccess < handle
% SignalAccess Implements common message signal operations.
%
%   This class is provided as a mixin that implements signal access operations
%   for message and message-like data items, such as J1939 parameter
%   groups. It provides:
%   
%       - Unpack/get signals using CANdbLib API
%       - Pack/set signals using CANdbLib API
%
%   See also VNT.

% Authors: Jaremy Pyle
% Copyright 2015 The MathWorks, Inc.
  
properties (Abstract, Hidden, SetAccess = protected)
    % PrivateData - Array of data bytes for the item.
    PrivateData
    % PrivateDatabase - A can.Database object defining the item.
    PrivateDatabase
    % PrivateName - The name of the item per the database definition.
    PrivateName
end

methods (Abstract, Access = protected)
    
    validity = isSignalValid(obj, signalIndex)
    % isSignalValid Verifies signal integrity.
    %
    %   This method is used to perform any required signal integrity
    %   checking needed when reading or writing signals values.

end

methods (Access = protected)
    
    function result = getSignalValues(obj)
    % getSignalValues Unpacks all signals for an item using the database.
    %
    %   This method implements a full unpack of all signal values from the
    %   provided item. It works for CAN messages and J1939 parameter
    %   groups. It returns a structure with a field for each signal or
    %   empty in the event of an issue. It uses the underlying database
    %   object to perform the operation.
        
        % Verify the message is of physical type. When the message is
        % configured as a raw message, there are no signal values
        % to reference, so the Signals property is irrelevant.
        if strcmpi(obj.PrivateName, '')
            result = [];
            return;
        end
        
        % Call to the database interface to unpack the signal values
        % for this item and return the resulting structure containing 
        % named fields for each signal.
        [status, statusText, result] = obj.PrivateDatabase.getSignalValueAll( ...
            obj.PrivateName, ...
            obj.PrivateData);
        
        % Check the returned status.
        obj.checkStatus(status, statusText);
        
        % Get the field names of the signals in the item.
        signalNames = fieldnames(result);
        
        % If the structure is received back from the database interface
        % with no fields, it means no signals are defined for this
        % message in the database file. In that case, return the
        % property value as empty instead of the blank structure.
        if isempty(signalNames)
            result = [];
        end
        
        % Loop through and check the integrity of each signal.
        for ii = 1:numel(signalNames)
            % Perform any required signal integrity verification.
            if ~obj.isSignalValid(ii)
                % Negate the value of this specific signal.
                result.(signalNames{ii}) = [];
            end
        end
    end
    
    function setSignalValues(obj, value)
    % setSignalValues Packs signals for an item using the database.
    %
    %   This method implements a pack of all changed signal values from the
    %   provided item. It works for CAN messages and J1939 parameter
    %   groups. It uses the underlying database object to perform the 
    %   operation.

        % Verify the item is of physical type. The Signals property
        % is only relevant when item has a database definition.
        if strcmpi(obj.PrivateName, '')
            error(message('vnt:SignalAccess:NoDatabaseAttached'));
        end
        
        % Verify that the value to set is a structure. Changing the
        % type or definition of the property away from a structure is
        % not allowed.
        if ~isstruct(value)
            error(message('vnt:SignalAccess:StructureInputRequired'));
        end
        
        % OPTIMIZATION: Read the signal names for this item from the 
        % database object.
        msgInfo = obj.PrivateDatabase.messageInfo(obj.PrivateName);
        signalNames = msgInfo.Signals;

        % Verify that the fields of the input structure match the
        % signal names defined in the database. A mismatch means the
        % user is trying to set a field that doesn't exist for the item.
        if ~isequal(sort(fields(value)), signalNames)
            error(message('vnt:SignalAccess:SignalDoesNotExist'));
        end
        
        % Read the current value of all the signals. This is used to
        % compare against the new value in order to determine which
        % signals have changed.
        [~, ~, currentValue] = obj.PrivateDatabase.getSignalValueAll( ...
            obj.PrivateName, ...
            obj.PrivateData);
        
        % Process each signal of the item.
        for ii = 1:numel(signalNames)
            % Only set the signal when the new value differs from the current.
            if value.(signalNames{ii}) == currentValue.(signalNames{ii})
                continue;
            end
            
            % Validate the values of each field of the structure. Only
            % numeric values are accepted as all data is fundamentally
            % numeric. We do not know specifically which field of the
            % structure is being changed, so we validate them all.
            if ~isnumeric(value.(signalNames{ii}))
                error(message('vnt:SignalAccess:InvalidSignalValue'));
            end
            
            % Perform any required signal integrity verification.
            if ~obj.isSignalValid(ii)
                error(message('vnt:SignalAccess:InvalidSignal'));
            end
            
            % Call to the database interface to pack the new signal values
            % for this item and set the resulting data array.
            [status, statusText, obj.PrivateData] = obj.PrivateDatabase.setSignalPhysicalValue( ...
                obj.PrivateName, ...
                signalNames{ii}, ...
                obj.PrivateData, ...
                value.(signalNames{ii}));
            
            % Check the returned status.
            obj.checkStatus(status, statusText);
        end
    end
    
end

methods (Access = private)

    function checkStatus(obj, status, statusText) %#ok<INUSL>
        
        % Validate that the signal operation was correct.
        %   - Note a value of 0 is success.
        %   - A value of 4 means out of range; however, this does not
        %     indicate an error. It indicates that the raw signal
        %     value scaled to value defined as out of range for the
        %     signal. We apply min/max capping in the MEX function,
        %     so a range error is not an error.
        %   - A value of 5 indicates a mode error. This is generally
        %     because the current mode signal for a multiplexed signal
        %     is not currently for this signal. We do no treat this as
        %     an error. We leave it to the user to determine
        %     appropriate mode and usage.
        if status ~= 0 && status ~= 4 && status ~= 5
            % Error if the signal operation failed.
            error(message('vnt:SignalAccess:CANdbLibError', status, statusText));
        end
    end
    
end

end