gusucode.com > vnt工具箱matlab源码程序 > vnt/vnt/+j1939/ParameterGroup.m
classdef ParameterGroup < hgsetget & ... matlab.mixin.CustomDisplay & ... vnt.internal.mixin.message.Extractions & ... vnt.internal.mixin.message.SignalAccess % ParameterGroup Handle to a J1939 parameter group. % % This class represents a J1939 parameter group. It contains properties to % act as a parameter group using CAN database files providing a signals % based interface. The methods provided by the class allow for % manipulation of parameter group data as well as various analysis % assisting functionality. % % See also VNT. % Authors: Jaremy Pyle % Copyright 2015 The MathWorks, Inc. properties (SetAccess = 'private') % PGN - The J1939 parameter group number address of this parameter group. PGN % PDUFormatType - The J1939 protocol data unit format of this parameter group. PDUFormatType end properties (Dependent) % Priority - The J1939 priority of this parameter group. Priority % SourceAddress - The J1939 source address of this parameter group. SourceAddress % DestinationAddress - The J1939 destintation address of this parameter group. DestinationAddress % Data - Parameter group data array. Data % Signals - A structure of the signals contained within the % parameter group with a named field for each signal. Signals end properties (Dependent, SetAccess = 'private') % ID - The numeric CAN identifier of the parameter group. ID % Name - The symbolic name of the parameter group. Name % Database - A handle to a CAN database file containing parameter group and % signal information for this parameter group. Database % Timestamp - The hardware logged time of reception for the parameter group. Timestamp end properties % UserData - Storage for custom information. UserData end properties (SetAccess = 'private', GetAccess = 'private') % DatabaseLength - The length in bytes of the message as defined in the % database file. DatabaseLength % SignalEndBit - An array of values containing the ending bit % number of each signal in the parameter group. SignalEndBit % Version - Indicates the version number of the class for % determining the difference between current and out of date % versions of parameter group objects. Version end % Internal property private storage. Used because some properties are % related in their set/get operations and to bypass the overhead of % validation when referencing properties internally. properties (Hidden, SetAccess = protected) PrivatePriority PrivateSourceAddress PrivateDestinationAddress PrivateID PrivateExtended = true; PrivateError = false; PrivateRemote = false; PrivateTimestamp PrivateData PrivateDatabase PrivateName end properties (Hidden, Dependent, SetAccess = protected) PrivateRawStruct end methods function obj = ParameterGroup(varargin) % Message Construct a J1939 parameter group. % Validate the input arguments. narginchk(2, 2); % Copy the input to local variables. database = varargin{1}; % Build the parameter group directly from a structure. % PG = ParameterGroup(DATABASE, STRUCT) if isstruct(varargin{2}) % Copy the input to local variables. msgStruct = varargin{2}; % Create parameter group objects equal in count to the number of % structures received which will be configured and % returned from the constructor. obj = j1939.ParameterGroup.newarray(1, numel(msgStruct)); % Build a logical array for removing non-J1939 entries. removeIndexes(numel(msgStruct)) = false; % Curate the structures for J1939 details. for ii = 1:numel(msgStruct) % If the entry is not an extended identifier or is an error % or remote frame then flag to remove this entry. if ~msgStruct(ii).Extended || msgStruct(ii).Error || msgStruct(ii).Remote removeIndexes(ii) = true; continue; end % Parse out the PGN from the ID, along with other % parameters that may be required later. msgStruct(ii).ID = uint32(msgStruct(ii).ID); [priority, sourceAddress, destinationAddress, pgn] = ... mexJ1939Utility('getSubsetForConstruction', msgStruct(ii).ID); % Check for this PGN in the database. msgInfo = privateMessageInfoByPGN(database, pgn); % If the PGN was not found, flag to remove this entry. if isempty(msgInfo) removeIndexes(ii) = true; continue; end % Load the pertinent J1939 identifier parameters. obj(ii).PrivatePriority = priority; obj(ii).PrivateSourceAddress = sourceAddress; obj(ii).PGN = msgInfo.J1939.PGN; % Set some values depending on the protocol data unit type. if msgInfo.J1939.PDUFormatType == 1 % For PDU type 1, the destination address is used. obj(ii).PrivateDestinationAddress = destinationAddress; obj(ii).PDUFormatType = j1939.Utility.PDUFormatType1; else % For PDU type 2, destination address is not used. obj(ii).PrivateDestinationAddress = j1939.Utility.DestinationAll; obj(ii).PDUFormatType = j1939.Utility.PDUFormatType2; end % Load the general parameters. obj(ii).PrivateID = msgStruct(ii).ID; obj(ii).PrivateTimestamp = msgStruct(ii).Timestamp; obj(ii).PrivateData = msgStruct(ii).Data; obj(ii).PrivateDatabase = database; obj(ii).PrivateName = msgInfo.Name; obj(ii).Version = 1.0; % Load the signal integrity details. obj(ii).DatabaseLength = msgInfo.Length; obj(ii).calculateSignalDetails(msgInfo); end % Remove the non-J1939 entries from the output array. obj(removeIndexes) = []; % Create a single J1939 parameter group object from database information. % PG = ParameterGroup(DATABASE, NAME) else % Copy the input to local variables. msgName = varargin{2}; % Validate the database argument. if ~isa(database, 'can.Database') || ~database.Usable error(message('vnt:J1939:InvalidDatabase')); end % Ensure that the supplied database is for a J1939 network. if ~database.DatabaseTypeJ1939 error(message('vnt:J1939:DatabaseNotJ1939')); end % Validate the name argument. validateattributes(msgName, {'char'}, ... {'nonempty', 'row'}, ... 'Message', 'NAME'); % Check for the parameter group in the database. msgInfo = privateMessageInfoByName(database, msgName); % Error on an unfound parameter group. if isempty(msgInfo) error(message('vnt:J1939:ParameterGroupNotFoundInDatabase')); end % Load the pertinent J1939 identifier parameters. obj.PrivatePriority = msgInfo.J1939.Priority; obj.PrivateSourceAddress = msgInfo.J1939.SourceAddress; obj.PGN = msgInfo.J1939.PGN; % Set some values depending on the protocol data unit type. if msgInfo.J1939.PDUFormatType == 1 % For PDU type 1, the destination address is used. obj.PrivateDestinationAddress = msgInfo.J1939.PDUSpecific; obj.PDUFormatType = j1939.Utility.PDUFormatType1; else % For PDU type 2, destination address is not used. obj.PrivateDestinationAddress = j1939.Utility.DestinationAll; obj.PDUFormatType = j1939.Utility.PDUFormatType2; end % Load the general parameters. obj.PrivateID = uint32(msgInfo.ID); obj.PrivateTimestamp = 0; obj.PrivateData = repmat(j1939.Utility.FillByte, 1, msgInfo.Length); obj.PrivateDatabase = database; obj.PrivateName = msgInfo.Name; obj.Version = 1.0; % Load the signal integrity details. obj.DatabaseLength = msgInfo.Length; obj.calculateSignalDetails(msgInfo); end end function [extracted, remainder] = extractAll(obj, value) % extractAll Returns all occurrences of the specified parameter group(s). % % [EXTRACTED, REMAINDER] = extractAll(PG, PG_NAMES) parses the given % array PG and returns all parameter groups found with the matched PG_NAMES. % % Inputs: % PG - The parameter groups to parse. % PG_NAMES - The string name(s) of the parameter groups to extract. % % Outputs: % EXTRACTED - A parameter group array containing all found instances of % the given group(s). If no matches were found, then EXTRACTED % will return as empty. % REMAINDER - A parameter group array containing all groups from the % original PG array not matching the specified input. % % Note that PG_NAMES can be given as a cell array. For example, if PG_NAMES % is passed as {'PG_NAME1' 'PG_NAME2'}, extractAll returns every instance of % both parmaeter groups as found in the PG array. % % Also note that REMAINDER is an optional output. If a variable for % REMAINDER is not specified, only the extracted parameter groups are returned. % % Examples: % [extractedPGs, remainder] = extractAll(parameterGroups, 'PG1') % extractedPGs = extractAll(parameterGroups, 'PG1') % [extractedPGs, remainder] = extractAll(parameterGroups, {'PG1' 'PG2'}) % % See also VNT. % Check the argument count. narginchk(2, 2); % Validate the input and convert from numbers to names. desiredNames = obj.validatePGInput(value); % Run the extraction using the mixin method. [extracted, remainder] = obj.doExtractAllByName(desiredNames); end function extracted = extractRecent(obj, varargin) % extractRecent Returns the most recent occurrence of the specified parameter group(s). % % EXTRACTED = extractRecent(PG) parses the array PG and returns % the most recent instance of each unique parameter group found % in the array. % % EXTRACTED = extractRecent(PG, PG_NAMES) parses the given % array PG and returns the most recent instance of parameter groups % found with the matched PG_NAMES. % % Inputs: % PG - The parameter groups to parse. % PG_NAMES - The string name(s) of the parameter groups to extract. % % Outputs: % EXTRACTED - A parameter group array which are the most recent occurrence of % the requested group(s) based on the Timestamp. If no matches % were found, then EXTRACTED will return as empty. % % Note that PG_NAMES can be given as a cell array. For example, if PG_NAMES % is passed as {'PG_NAME1' 'PG_NAME2'}, extractAll returns every instance of % both parmaeter groups as found in the PG array. % % Examples: % extractedPGs = extractRecent(parameterGroups) % extractedPGs = extractRecent(parameterGroups, 'PG1') % extractedPGs = extractRecent(parameterGroups, {'PG1' 'PG2'}) % % See also VNT. % Check the argument count. narginchk(1, 2); if nargin == 1 % Get all of the unique names from the input objects. desiredNames = unique({obj.Name}); else % Validate the input and convert from numbers to names. desiredNames = obj.validatePGInput(varargin{1}); end % Run the extraction using the mixin method. extracted = obj.doExtractRecentByName(desiredNames); end function extracted = extractTime(obj, startTime, endTime) % extractTime Returns all parameter groups having occurred within a time period. % % EXTRACTED = extractTime(PG, STARTTIME, ENDTIME) parses the % array PG and returns all parameter groups found to be within % the time period bounded inclusively by STARTTIME and ENDTIME. % % Inputs: % PG - The parameter groups to parse. % STARTTIME - The beginning of the time range specified in seconds. % ENDTIME - The end of the time range specified in seconds. % % Outputs: % EXTRACTED - A parameter group array containing all parameter % groups having timestamps within the specified time range. If % no groups are found within the time range, EXTRACTED returns % as empty. % % Note that the time range specified must be given in increasing order % from STARTTIME to ENDTIME. Inf is also an accepted value for ENDTIME % to specify the largest available time. 0 is the earliest accepted % STARTTIME. % % Examples: % extractedPGs = extractTime(parameterGroups, 5, 10.5) % extractedPGs = extractTime(parameterGroups, 0, 60) % extractedPGs = extractTime(parameterGroups, 150, Inf) % % See also VNT. % Check the argument count. narginchk(3, 3); % Validate startTime and endTime. validateattributes(startTime, {'numeric'}, ... {'finite', 'nonempty', 'nonnan', 'nonnegative', ... 'nonsparse', 'real', 'scalar'}, ... 'extractTime', 'STARTTIME'); validateattributes(endTime, {'numeric'}, ... {'nonempty', 'nonnan', 'nonnegative', 'nonsparse', ... 'real', 'scalar'}, ... 'extractTime', 'ENDTIME'); % Validate that the start time is earlier than the end time. if (startTime > endTime) error(message('vnt:J1939:InvalidTimeRange')); end % Run the extraction using the mixin method. extracted = obj.doExtractByTime(startTime, endTime); end function out = get.Priority(obj) out = obj.PrivatePriority; end function set.Priority(obj, value) % Validate the new value. validateattributes(value, {'numeric'}, ... {'finite', 'nonempty', 'nonnan', 'nonnegative', ... 'nonsparse', 'real', 'scalar', '>=', 0, '<=', 7}, ... 'set.Priority', 'VALUE'); % Store the property value in its internal property. obj.PrivatePriority = uint32(value); % Set the value into the J1939 parameter group identifier. obj.PrivateID = j1939.Utility.setPDUField('Priority', ... obj.PrivatePriority, ... obj.PrivateID); end function out = get.DestinationAddress(obj) out = obj.PrivateDestinationAddress; end function set.DestinationAddress(obj, value) % Validate the new value. validateattributes(value, {'numeric'}, ... {'finite', 'nonempty', 'nonnan', 'nonnegative', ... 'nonsparse', 'real', 'scalar', '>=', 0, '<=', 255}, ... 'set.DestinationAddress', 'VALUE'); % Only allow setting of the destination address when the parameter % group is of PDU format type 2. if strcmpi(obj.PDUFormatType, j1939.Utility.PDUFormatType2) error(message('vnt:J1939:DestinationAddressNotApplicable')); end % Store the property value in its internal property. obj.PrivateDestinationAddress = uint32(value); % Set the value into the J1939 parameter group identifier. obj.PrivateID = j1939.Utility.setPDUField('PDUSpecific', ... obj.PrivateDestinationAddress, ... obj.PrivateID); end function out = get.SourceAddress(obj) out = obj.PrivateSourceAddress; end function set.SourceAddress(obj, value) % Validate the new value. validateattributes(value, {'numeric'}, ... {'finite', 'nonempty', 'nonnan', 'nonnegative', ... 'nonsparse', 'real', 'scalar', '>=', 0, '<=', 255}, ... 'set.SourceAddress', 'VALUE'); % Store the property value in its internal property. obj.PrivateSourceAddress = uint32(value); % Set the value into the J1939 parameter group identifier. obj.PrivateID = j1939.Utility.setPDUField('SourceAddress', ... obj.PrivateSourceAddress, ... obj.PrivateID); end function out = get.Name(obj) out = obj.PrivateName; end function out = get.Database(obj) out = obj.PrivateDatabase; end function out = get.ID(obj) out = obj.PrivateID; end function out = get.Timestamp(obj) out = obj.PrivateTimestamp; end function out = get.Data(obj) out = obj.PrivateData; end function set.Data(obj, value) % Validate the new value for proper type. validateattributes(value, {'numeric'}, ... {'finite', 'integer', 'nonempty', 'nonnan', 'nonnegative', ... 'nonsparse', 'real', 'row'}, ... 'set.Data', 'VALUE'); % Some parameter groups in J1939 allow for variable length data, % so we allow changing of the data length by the user. We do warn % though if the length is changed to something different than what % is defined in the database just in case the change was being made % in error. if numel(value) ~= obj.DatabaseLength warning(message('vnt:J1939:DataLengthChanged')); end % Set the property while casting to uint8 type. obj.PrivateData = uint8(value); end function out = get.Signals(obj) % Use the mixin function to get the signal values. out = obj.getSignalValues(); end function set.Signals(obj, value) % Use the mixin function to set the signal values. obj.setSignalValues(value); end function out = get.PrivateRawStruct(obj) % Return a structure of the base fields required to minimally % represent this parameter group as a CAN message. out.ID = obj.PrivateID; out.Extended = obj.PrivateExtended; out.Error = obj.PrivateError; out.Remote = obj.PrivateRemote; out.Timestamp = obj.PrivateTimestamp; out.Data = obj.PrivateData; end end methods (Access = protected) function group = getPropertyGroups(obj) %#ok<MANU> % getPropertyGroups Build custom display for the class. % Build the property sections for display. title1 = sprintf('Protocol Data Unit Details:\n ---------------------------'); plist1 = {'Name', 'PGN', 'Priority', 'PDUFormatType', 'SourceAddress', 'DestinationAddress'}; title2 = sprintf('Data Details:\n -------------'); plist2 = {'Timestamp', 'Data', 'Signals'}; title3 = sprintf('Other Information:\n ------------------'); plist3 = {'UserData'}; % Set the property groups. group(1) = matlab.mixin.util.PropertyGroup(plist1, title1); group(2) = matlab.mixin.util.PropertyGroup(plist2, title2); group(3) = matlab.mixin.util.PropertyGroup(plist3, title3); end function 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. In the % case of a J1939 parameter group, this method is used to invalidate % any signals for which there is not enough to actually determine % their value in the case of variable length data. % Check signal integrity. Due to some parameter groups having % variable length data, not all defined signals may be validaly % unpacked. The Vector CANdbLib will unpack every signal though % regardless of length. We want to check for any signals with % locations outside the data array and invalidate them. % Calculate the number of bits in this parameter group data array. bitLength = numel(obj.PrivateData) * 8; % Check the end bit location of the specified signal against % the bit length of the data. if obj.SignalEndBit(signalIndex) > bitLength % It falls outside, so invalidate the signal. validity = false; else % It falls inside, so the signal is valid. validity = true; end end end methods (Access = private) function pgNameList = validatePGInput(obj, pgInput) %#ok<INUSL> % validatePGInput Check parameter group input for methods. % % This method is used to validate parameter group input for class % methods that take parameter groups as names or numbers. It % validates and errors is applicable. It returns a cell array of the % parameter group names, converting from numbers if required. % Do processing for parameter group names. if ischar(pgInput) || iscell(pgInput) % For a single name, convert to cell array as further % processing requires cell array input. if ~iscell(pgInput) pgNameList = {pgInput}; else pgNameList = pgInput; end % Validate that each entry in the cell is a string. for ii = 1:numel(pgNameList) validateattributes(pgNameList{ii}, {'char'}, ... {'nonempty', 'row'}, 'extractAll', 'NAME'); end else % Error for invalid input. error(message('vnt:J1939:InvalidParameterGroupInput')); end end function calculateSignalDetails(obj, msgInfo) % calculateSignalDetails Sets signal end bit. % % This method is used to calculate and store the end bits for % signals in the object. These values are used for signal integrity % purposes when signals are accessed. % Check each signal in the parameter group. for ii = 1:numel(msgInfo.Signals) % Get the end bit for the signal. Note we have to adjust for % bit logistics and endian type. Also adjust for 0 versus 1 % indexing from CANdb to MATLAB. switch msgInfo.SignalInfo(ii).ByteOrder case 'LittleEndian' obj.SignalEndBit(ii) = msgInfo.SignalInfo(ii).StartBit ... + msgInfo.SignalInfo(ii).SignalSize; case 'BigEndian' obj.SignalEndBit(ii) = msgInfo.SignalInfo(ii).StartBit + 1; end end end end methods (Hidden) function delete(obj) %#ok<INUSD> % delete Delete the J1939 parameter group object. end end methods (Static, Hidden) function obj = loadobj(obj) % loadobj Load a J1939 parameter group object. % Reconstruct the object. try obj = j1939.ParameterGroup(obj.Database, obj.Name); catch obj = j1939.ParameterGroup.empty(); end end end end