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