gusucode.com > vnt工具箱matlab源码程序 > vnt/vnt/+can/+kvaser/Channel.m

    classdef Channel < can.Channel
% Channel Connection to a Kvaser CAN device channel.
%
%   The Channel class provides connectivity to CAN channels for Kvaser 
%   devices. It contains properties and methods to configure and use the 
%   channel on a network.
%
%   See also VNT.

% Authors: JDP
% Copyright 2009-2015 The MathWorks, Inc.
    
% Note that all uncommented properties are Abstract and inherit their
% help from the super class.

properties (SetAccess = 'private', GetAccess = 'protected')
    AsyncioChannel
    AsyncioReplayChannel
end

properties (Dependent, SetAccess = 'private')
    % BusLoad - The utilization level of the bus as a percentage.
    BusLoad
end

properties (Dependent, SetAccess = 'private')
    BusSpeed
    NumOfSamples
    SJW
    TSEG1
    TSEG2
end

properties (Dependent, SetAccess = 'private')
    BusStatus
end

properties (SetAccess = 'private')
    Device
    DeviceChannelIndex
    DeviceSerialNumber
    DeviceVendor
end

properties (SetAccess = 'private', GetAccess = 'private')
    % DeviceCode - The vendor specific code for the connected device.
    DeviceCode
    % DeviceIndex - A numeric index to the connected devices used to
    %   address the proper one if more than one of the same device are
    %   connected. This value is parsed out of Device and stored
    %   separately for easier internal access.
    DeviceIndex
end

properties (SetAccess = 'private', GetAccess = 'private')
    % Handle - The handle value used for access within the Kvaser
    %   driver to access the device represented by the channel.
    Handle
end

properties (SetAccess = 'protected')
    InitializationAccess
    InitialTimestamp
end

properties (Dependent, SetAccess = 'private')
    ReceiveErrorCount
    TransmitErrorCount
end

properties (SetAccess = 'private', GetAccess = 'protected')
    ReceiveQueueSize
    TransmitQueueSize
end

properties (Dependent)
    SilentMode
end

properties (Dependent, SetAccess = 'private')
    TransceiverName
end

properties (Dependent)
    TransceiverState
end

properties (SetAccess = 'private', GetAccess = 'protected')
    MultipleAccessAllowed = true;
    Usable = false;
end

properties
    UserData
end


methods
    
    function obj = Channel(varargin)
    % Channel Construct a connection to a Kvaser CAN device.
        
        % Check the argument count.
        narginchk(3,3);
        
        % Put the input arguments into local variables.
        inVendor = varargin{1};
        inDevice = varargin{2};
        inDeviceChannelIndex = varargin{3};
        
        % Validate the device string.
        validateattributes(inDevice, {'char'}, ...
            {'nonempty', 'row'}, 'Channel', 'DEVICE');
        
        % Parse the individual pieces of the device string.
        deviceParts = textscan(inDevice, '%s');
        deviceParts = cat(1, deviceParts{:})';
        deviceIndex = str2double(deviceParts{end});
        
        % Validate the device index piece of the device string.
        try
            validateattributes(deviceIndex, ...
                {'numeric'}, ...
                {'finite', 'integer', 'nonempty', 'nonnan', ...
                 'nonsparse', 'positive', 'real', 'scalar'});
        catch err %#ok<NASGU>
            error(message('vnt:Channel:InvalidDeviceIndex'));
        end
        
        % Validate the device channel index.
        validateattributes(inDeviceChannelIndex, ...
            {'numeric'},...
            {'finite', 'integer', 'nonempty', 'nonnan', ...
             'nonsparse', 'positive', 'real', 'scalar'}, ...
            'Channel', 'DEVICECHANNELINDEX');
        
        % Put the device name back together, but leave off the last
        % entry of the string which is the device index.
        deviceName = deviceParts{1};
        for ii = 2:(numel(deviceParts) - 1)
            deviceName = [deviceName ' ' deviceParts{ii}]; %#ok<AGROW>
        end
        
        % Verify if the requested device is supported by the toolbox.
        if ~can.kvaser.Utility.isDeviceSupported(deviceName)
            error(message('vnt:Channel:UnsupportedDevice'));
        end
        
        % Set the device identification properties.
        obj.DeviceVendor = inVendor;
        obj.DeviceChannelIndex = inDeviceChannelIndex;
        deviceName = can.kvaser.Utility.translateDeviceName(deviceName);
        obj.Device = [deviceName ' ' num2str(deviceIndex)];
        obj.DeviceIndex = deviceIndex;
        obj.DeviceCode = can.kvaser.Utility.translateDeviceCode(deviceName);
        
        % Open the vendor library.
        can.kvaser.CANLib.canInitializeLibrary();
        
        % Get channel data for this device and channel.
        channelData = can.kvaser.Utility.getDriverData(...
            obj.DeviceCode,...
            obj.DeviceIndex,...
            obj.DeviceChannelIndex);
        
        if isempty(channelData)
            error(message('vnt:Channel:DeviceNotFound'));
        end
        
        % Set the device serial number.
        obj.DeviceSerialNumber = channelData.CardSerialNumber;
        
        % Get a handle to the device channel.
        [obj.Handle, obj.InitializationAccess] = ...
            can.kvaser.CANLib.canOpenChannel(channelData.ChannelNumber);
        
        % Set for proper timestamp scaling for received messages.
        can.kvaser.CANLib.canIoCtl(obj.Handle, 6, 1);
        
        % Turn on reception of messages by this channel for messages
        % sent by this channel.
        can.kvaser.CANLib.canIoCtl(obj.Handle, 7, 1);
        
        % Turn on advanced access error reporting.
        can.kvaser.CANLib.canIoCtl(obj.Handle, 20, 1);
        
        % Set the queue sizes.
        obj.ReceiveQueueSize = 1024;
        obj.TransmitQueueSize = 256;
        
        % Determine the path for all asyncio plugins.
        arch = computer('arch');
        devicePath = fullfile(toolboxdir('vnt'), 'vnt', 'private', arch, 'kvasercanlibplugin');
        converterPath = fullfile(toolboxdir('vnt'), 'vnt', 'private', arch, 'canmlconverter');
        
        % Create the asyncio object for normal receive and transmit.
        asyncioOptions.Handle = obj.Handle;
        asyncioOptions.ReceiveCapable = true;
        asyncioOptions.TransmitCapable = true;
        asyncioOptions.ReplayCapable = false;
        
        obj.AsyncioChannel = asyncio.Channel( ...
            devicePath, converterPath, asyncioOptions, [Inf, 0]);
        
        % Create the asyncio replay object.
        asyncioOptions.ReceiveCapable = false;
        asyncioOptions.TransmitCapable = true;
        asyncioOptions.ReplayCapable = true;

        obj.AsyncioReplayChannel = asyncio.Channel( ...
            devicePath, converterPath, asyncioOptions, [Inf, Inf]);
        
        % Set the object usable.
        obj.Usable = true;
    end
    
    function configBusSpeed(obj, varargin)
    % configBusSpeed Set the bit timing of a CAN channel.
    %
    %   configBusSpeed(CHANNEL, BUSSPEED) sets the speed of the CHANNEL
    %   to BUSSPEED in a direct form that uses default bit timing
    %   calculation factors.
    %
    %   configBusSpeed(CHANNEL, BUSSPEED, SJW, TSEG1, TSEG2, NUMBEROFSAMPLES)
    %   sets the speed of the CHANNEL to BUSSPEED using specified bit
    %   timing calculation factors in an advanced form.
    %
    %   Inputs:
    %       BUSSPEED -  The speed of a network in bits per second.
    %       SJW - The Synchronization Jump Width which helps define the
    %           length of a bit on a network.
    %       TSEG1 - Time Segment 1 which defines the section before
    %           a bit is sampled on a network.
    %       TSEG2 - Time Segment 2 which defines the section after
    %           a bit is sampled on a network.
    %       NUMBEROFSAMPLES - The count of samples used for determining
    %           the bit state of a network.
    %
    %   Note that unless you have specific timing requirements provided
    %   for your network, it is recommended to use the direct form of
    %   configBusSpeed. Also note that bit timing can only be set when
    %   the channel is offline and has initialization access to the device.
    %
    %   Examples:
    %       channel = canChannel('Kvaser', 'USBcan Professional 1', 1)
    %       configBusSpeed(channel, 250000)
    %
    %       channel = canChannel('Kvaser', 'USBcan Professional 1', 1)
    %       configBusSpeed(channel, 500000, 1, 4, 3, 1)
    %
    %   See also VNT.
        
        % Check the argument count.
        if ((nargin ~= 2) && (nargin ~= 6))
            error(message('vnt:Channel:IncorrectArgumentCount'));
        end
        
        % Validate the channel before using its functionality.
        assertValidity(obj);
        
        % Check if the channel has initialization access.
        if ~obj.InitializationAccess
            error(message('vnt:Channel:NoInitAccessToChannel'));
        end
        
        % Verify that the channel is offline.
        if obj.Running
            error(message('vnt:Channel:ChannelNotOffline'));
        end
        
        % Validate the busSpeed.
        validateattributes(varargin{1}, ...
            {'numeric'}, ...
            {'integer', 'nonempty', 'nonnan', 'nonsparse', 'real', ...
             'scalar', '>=', 8000, '<=', 1000000}, ...
            'configBusSpeed', 'BUSSPEED');
        
        % Set the bit timing in direct form by only providing the bus
        % speed when two arguments are provided.
        if nargin == 2
            % Set the bit timing in direct form.
            can.kvaser.CANLib.canSetBitrate(obj.Handle, varargin{1});
            
        % Set the bit timing in advanced form by providing calculation
        % factors when six arguments are provided.
        elseif nargin == 6
            % Validate the other input arguments.
            validateattributes(varargin{2}, {'numeric'}, ...
                {'finite', 'integer', 'nonempty', 'nonnan', ...
                 'nonnegative', 'nonsparse', 'real', 'scalar'}, ...
                'configBusSpeed', 'SJW');
            validateattributes(varargin{3}, {'numeric'}, ...
                {'finite', 'integer', 'nonempty', 'nonnan', ...
                 'nonnegative', 'nonsparse', 'real', 'scalar'}, ...
                'configBusSpeed', 'TSEG1');
            validateattributes(varargin{4}, {'numeric'}, ...
                {'finite', 'integer', 'nonempty', 'nonnan', ...
                 'nonnegative', 'nonsparse', 'real', 'scalar'}, ...
                'configBusSpeed', 'TSEG2');
            validateattributes(varargin{5}, {'numeric'}, ...
                {'finite', 'integer', 'nonempty', 'nonnan', ...
                 'nonnegative', 'nonsparse', 'real', 'scalar'}, ...
                'configBusSpeed', 'NUMOFSAMPLES');
            
            % The Kvaser CANLib currently does not perform adequate
            % validation on advanced bus speed settings. When setting
            % in advanced mode, we want to first set the bus speed in
            % direct form and use that operation to validate the bus
            % speed value. Once proper validation is done in their
            % driver, this extra validation on our part can be removed.
            can.kvaser.CANLib.canSetBitrate(obj.Handle, varargin{1});
            
            % Set the bit timing in advanced form.
            can.kvaser.CANLib.canSetBusParams(obj.Handle, ...
                varargin{1},... % Bus speed.
                varargin{3},... % TSEG1.
                varargin{4},... % TSEG2.
                varargin{2},... % SJW.
                varargin{5});   % Number of samples.
        end
    end
    
    function disp(obj)
        % Validate the channel before using its functionality.
        assertValidity(obj);
        
        % Display a top level summary.
        fprintf(1, 'Summary of CAN Channel using ''%s'' ''%s'' Channel %d.\n\n',...
            obj.DeviceVendor,...
            obj.Device,...
            obj.DeviceChannelIndex);
        
        % Display basic configuration parameters.
        fprintf(1, '  Channel Parameters:  Bus Speed is %d.\n', obj.BusSpeed);
        fprintf(1, '%23sBus Status is ''%s''.\n', '', obj.BusStatus);
        fprintf(1, '%23sTransceiver name is ''%s''.\n', '', obj.TransceiverName);
        fprintf(1, '%23sSerial Number of this device is %d.\n', '', obj.DeviceSerialNumber);
        
        % Display the initialization access status.
        if obj.InitializationAccess
            fprintf(1, '%23sInitialization access is allowed.\n', '');
        else
            fprintf(1, '%23sInitialization access is not allowed.\n', '');
        end
        
        % Display the currently attached database.
        if isempty(obj.Database)
            fprintf(1, '%23sNo database is attached.\n\n', '');
        else
            fprintf(1, '%23s''%s.dbc'' database is attached.\n\n', '', obj.Database.Name);
        end
        
        % Display the current channel status.
        if obj.Running
            fprintf(1, '%14sStatus:  Online.\n', '');
            fprintf(1, '%23s%3.2f%% Bus Load.\n', '', obj.BusLoad);
        else
            fprintf(1, '%14sStatus:  Offline - Waiting for start.\n', '');
        end
        
        % Display message transmit and receive information.
        fprintf(1, '%23s%d messages available to receive.\n', '', obj.MessagesAvailable);
        fprintf(1, '%23s%d messages transmitted since last start.\n', '', obj.MessagesTransmitted);
        fprintf(1, '%23s%d messages received since last start.\n\n', '', obj.MessagesReceived);
        
        % Display a filter history section with the first entry in the log.
        fprintf(1, '      Filter History:  %s\n', obj.FilterHistory);
        
        % Add a final line for spacing.
        fprintf(1, '\n');
    end
    
    function getdisp(obj)
        % Validate the channel before using its functionality.
        assertValidity(obj);
        
        % Display general information.
        fprintf(1, '\n  General Settings:\n');
        fprintf(1, '\tBusLoad = %3.2f\n', obj.BusLoad);
        fprintf(1, '\tBusStatus = ''%s''\n', obj.BusStatus);
        
        if isempty(obj.Database)
            fprintf(1, '\tDatabase = []\n');
        else
            fprintf(1, '\tDatabase = ''%s.dbc''\n', obj.Database.Name);
        end
        
        fprintf(1, '\tFilterHistory = ''%s''\n', obj.FilterHistory);
        fprintf(1, '\tInitializationAccess = %d\n', obj.InitializationAccess);
        fprintf(1, '\tMessageReceivedFcn = %s\n', can.Utility.callbackFcnToString(obj.MessageReceivedFcn));
        fprintf(1, '\tMessageReceivedFcnCount = %d\n', obj.MessageReceivedFcnCount);
        fprintf(1, '\tMessagesAvailable = %d\n', obj.MessagesAvailable);
        fprintf(1, '\tMessagesReceived = %d\n', obj.MessagesReceived);
        fprintf(1, '\tMessagesTransmitted = %d\n', obj.MessagesTransmitted);
        fprintf(1, '\tReceiveErrorCount = %d\n', obj.ReceiveErrorCount);
        fprintf(1, '\tRunning = %d\n', obj.Running);
        fprintf(1, '\tSilentMode = %d\n', obj.SilentMode);
        fprintf(1, '\tTransmitErrorCount = %d\n', obj.TransmitErrorCount);
        
        % Display device specific information.
        fprintf(1, '\n  Device Settings:\n');
        fprintf(1, '\tDevice = ''%s''\n', obj.Device);
        fprintf(1, '\tDeviceChannelIndex = %d\n', obj.DeviceChannelIndex);
        fprintf(1, '\tDeviceSerialNumber = %d\n', obj.DeviceSerialNumber);
        fprintf(1, '\tDeviceVendor = ''%s''\n', obj.DeviceVendor);
        
        % Display transceiver information.
        fprintf(1, '\n  Transceiver Settings:\n');
        fprintf(1, '\tTransceiverName = ''%s''\n', obj.TransceiverName);
        fprintf(1, '\tTransceiverState = %d\n', obj.TransceiverState);
        
        % Display bit timing information.
        fprintf(1, '\n  Bit Timing Settings:\n');
        fprintf(1, '\tBusSpeed = %d\n', obj.BusSpeed);
        fprintf(1, '\tSJW = %d\n', obj.SJW);
        fprintf(1, '\tTSEG1 = %d\n', obj.TSEG1);
        fprintf(1, '\tTSEG2 = %d\n', obj.TSEG2);
        fprintf(1, '\tNumOfSamples = %d\n\n', obj.NumOfSamples);
    end
    
    function setdisp(obj)
        % Validate the channel before using its functionality.
        assertValidity(obj);
        
        fprintf(1, '\n  Database = can.Database handle -or- empty\n');
        fprintf(1, '  MessageReceivedFcn = string -or- function handle -or- cell array\n');
        fprintf(1, '  MessageReceivedFcnCount\n');
        fprintf(1, '  SilentMode = [ {false} | true ]\n');
        fprintf(1, '  TransceiverState\n\n');
    end
    
    
    function out = get.BusLoad(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Request the status from the driver.
        can.kvaser.CANLib.canRequestBusStatistics(obj.Handle);
        
        % Read the status from the driver.
        busStatistics = can.kvaser.CANLib.canGetBusStatistics(obj.Handle);
        
        % Return the property value according to the current chip
        % state. The value is scaled to be a percentage.
        out = busStatistics.BusLoad / 100;
    end
    
    function out = get.BusStatus(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Request the status from the driver.
        can.kvaser.CANLib.canRequestChipStatus(obj.Handle);
        
        % Read the status from the driver.
        chipStatus = can.kvaser.CANLib.canReadStatus(obj.Handle);
        
        % Return the property value according to the current chip state.
        if ~obj.Running
            out = 'N/A';
        elseif chipStatus.ErrorActive
            out = 'ErrorActive';
        elseif chipStatus.ErrorWarning
            out = 'ErrorWarning';
        elseif chipStatus.ErrorPassive
            out = 'ErrorPassive';
        elseif chipStatus.BusOff
            out = 'BusOff';
        end
    end
    
    function out = get.ReceiveErrorCount(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Read the status from the driver.
        [~, out, ~] = can.kvaser.CANLib.canReadErrorCounters(obj.Handle);
    end
    
    function out = get.TransmitErrorCount(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Read the status from the driver.
        [out, ~, ~] = can.kvaser.CANLib.canReadErrorCounters(obj.Handle);
    end
    
    function out = get.SilentMode(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get the driver data.
        outputControlMode = can.kvaser.CANLib.canGetBusOutputControl(obj.Handle);
        
        % Return true or false for the property based on the channel
        % setting: canDRIVER_NORMAL 4, canDRIVER_SILENT 1.
        if outputControlMode == 1
            out = true;
        else
            out = false;
        end
    end
    
    function set.SilentMode(obj, newValue)
        % Validate the channel before using its functionality.
        assertValidity(obj);
        
        % Verify that the channel is offline.
        if obj.Running
            error(message('vnt:Channel:ChannelNotOffline'));
        end
        
        % Check if the channel has initialization access.
        if ~obj.InitializationAccess
            error(message('vnt:Channel:NoInitAccessToChannel'));
        end
        
        % Validate the new value.
        validateattributes(newValue, {'logical'}, {'scalar'}, ...
            'set.SilentMode', 'VALUE');
        
        % Determine the value to pass to the driver based on the value
        % provided: canDRIVER_NORMAL 4, canDRIVER_SILENT 1.
        if newValue
            outputControlMode = 1;
        else
            outputControlMode = 4;
        end
        
        % Set the property.
        can.kvaser.CANLib.canSetBusOutputControl(obj.Handle, outputControlMode);
    end
    
    function out = get.TransceiverName(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get channel data for this device and channel.
        channelData = can.kvaser.Utility.getDriverData(...
            obj.DeviceCode,...
            obj.DeviceIndex,...
            obj.DeviceChannelIndex);
        
        % Return the property value.
        out = channelData.TransceiverName;
    end
    
    function out = get.TransceiverState(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get the driver data.
        [out, ~, ~] = can.kvaser.CANLib.canGetDriverMode(obj.Handle);
    end
    
    function set.TransceiverState(obj, newValue)
        % Validate the channel before using its functionality.
        assertValidity(obj);
        
        % Validate the input argument newValue.
        validateattributes(newValue, {'numeric'}, ...
            {'finite', 'integer', 'nonempty', 'nonnan', ...
             'nonnegative', 'nonsparse', 'real', 'scalar'}, ...
            'set.TransceiverState', 'VALUE');
        
        % Set the property.
        can.kvaser.CANLib.canSetDriverMode(obj.Handle, newValue);
        
        % Check if the value of the property has been updated or been
        % reverted back to the last value by the driver.
        if newValue ~= obj.TransceiverState
            % Give a warning to the user.
            warning(message('vnt:Channel:ValueNotChanged'));
        end
    end
    
    function out = get.BusSpeed(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get and return the value for this property.
        [out, ~, ~, ~, ~] = can.kvaser.CANLib.canGetBusParams(obj.Handle);
    end
    
    function out = get.SJW(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get and return the value for this property.
        [~, ~, ~, out, ~] = can.kvaser.CANLib.canGetBusParams(obj.Handle);
    end
    
    function out = get.TSEG1(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get and return the value for this property.
        [~, out, ~, ~, ~] = can.kvaser.CANLib.canGetBusParams(obj.Handle);
    end
    
    function out = get.TSEG2(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get and return the value for this property.
        [~, ~, out, ~, ~] = can.kvaser.CANLib.canGetBusParams(obj.Handle);
    end
    
    function out = get.NumOfSamples(obj)
        % Validate the channel before using its functionality.
        if ~assertValidity(obj)
            % Return empty for any invalid object state.
            out = [];
            return;
        end
        
        % Get and return the value for this property.
        [~, ~, ~, ~, out] = can.kvaser.CANLib.canGetBusParams(obj.Handle);
    end
    
    function obj = saveobj(obj)
    % saveobj Saves the channel information to file.
    %
    %   OBJ = saveobj(OBJ) saves the channel for future loading. The
    %   channel information is saved as a structure to due to the
    %   nature of the channel's underlying connection to third party
    %   drivers and devices.
        
        % Set object properties into a structure for saving. Turn the
        % warning off to so that it does not show to the user.
        warnState = warning('OFF', 'MATLAB:structOnObject');
        saveInfo = struct(obj);
        warning(warnState);
        
        % Remove fields that should not be saved.
        saveInfo = rmfield(saveInfo, 'AsyncioChannel');
        saveInfo = rmfield(saveInfo, 'AsyncioReplayChannel');
        saveInfo = rmfield(saveInfo, 'CustomEventListener');
        saveInfo = rmfield(saveInfo, 'ReceiveCallbackListener');
        
        % Set the output to save.
        obj = saveInfo;
    end
    
end


methods (Access = 'protected')
    
    function onAsyncioCustomEvent(obj, ~, ~) %#ok<MANU>
    % onAsyncioCustomEvent Callback function for event occurrence.
    %
    %   onAsyncioCustomEvent(CANCH, SOURCE, DATA) is registered
    %   with the Asyncio layer and is called upon custom event.
        
    end
    
    function filterSetInternal(obj, code, mask, idType)
    % filterSetInternal Sets hardware filters.
    %
    %   This method is used internally by the hardware agnostic filtering
    %   code to employ use of the hardware filters. There is a performance
    %   benefit to block as many messages as possible via hardware filters
    %   before applying software filtering on the channel.
    
        % Check the filter type to be set.
        switch idType
            case 'Standard'
                % Set the type code for use in the driver function call.
                idTypeCode = 0;
            case 'Extended'
                % Set the type code for use in the driver function call.
                idTypeCode = 1;
        end        
        
        % Set the hardware filter.
        can.kvaser.CANLib.canSetAcceptanceFilter(obj.Handle, code, mask, idTypeCode);
    end
    
    function setInitialTimestamp(obj)
    % setInitialTimestamp Set the initial timestamp property value.

        % Convert the time value obtained from asyncio into a MATLAB
        % datetime object.
        obj.InitialTimestamp = can.Utility.calculateInitialTimestamp( ...
            obj.AsyncioChannel.InitialTimestamp);
    end
    
end


methods (Hidden)
    
    function delete(obj)
        % Stop the channel to ensure it offline when removed. The
        % channel is stopped in the asyncio layer directly.
        if ~isempty(obj.AsyncioReplayChannel)
            obj.AsyncioReplayChannel.close();
        end
        
        if ~isempty(obj.AsyncioChannel)
            obj.AsyncioChannel.close();
        end
        
        % Clean up any vendor driver links only if they were
        % initialized. This protects delete from generating errors on
        % partially failed construction.
        if ~isempty(obj.Handle)
            % Close the handle.
            can.kvaser.CANLib.canClose(obj.Handle);
        end
    end
    
end


methods (Static)
    
    function obj = loadobj(obj)
    % loadobj Load a channel from memory.
    %
    %   OBJ = loadobj(OBJ) loads the channel from memory. The
    %   information loaded comes as a structure from which a new
    %   channel is built and configured to look like the previously
    %   saved channel.
    %
    %   Note that if an error happens while attempting to reconnect or
    %   reconfigure the channel, an empty version of the channel is
    %   returned. The empty object will not reach the user though. The
    %   MATLAB object system will reconstruct an invalid version of the
    %   channel with empty properties. Returning empty is done simply
    %   to avoid a class type warning in the event of a load error.
        
        % Collect device information.
        info = canHWInfo();
        
        % Determine if the vendor of the device for the channel
        % being loaded has devices currently installed on the system.
        vendorIndex = strmatch(...
            lower(obj.DeviceVendor),...
            lower({info.VendorInfo.VendorName}),...
            'exact');
        
        % Check for no match on the vendor.
        if isempty(vendorIndex)
            % Warn the user of the load issue.
            warning(message('vnt:Channel:CannotReconnectToDriver'));
            % Return an empty version of the channel.
            obj = can.kvaser.Channel.empty();
            return;
        end
        
        % Create a list of device codes for matching the loaded
        % channel's device to what is currently available.
        deviceList = {info.VendorInfo(vendorIndex).ChannelInfo.Device};
        for ii = 1:numel(deviceList)
            % Get the individual string pieces of the device string.
            deviceParts = textscan(deviceList{ii}, '%s');
            deviceParts = cat(1, deviceParts{:})';
            
            % Get the actual device name, which means remove the device
            % index off the end fo the device string.
            deviceKey = deviceParts{1};
            for jj = 2:(numel(deviceParts) - 1)
                deviceKey = [deviceKey ' ' deviceParts{jj}]; %#ok<AGROW>
            end
            
            % Reference the device code for this device name.
            deviceCodes(ii) = can.kvaser.Utility.translateDeviceCode(deviceKey); %#ok<AGROW>
        end
        
        % Determine if the device is available to which the channel
        % being loaded was originally connected. This is done by
        % matching the serial number and channel index for the device
        % as well as the vendor device code.
        channelInfo = info.VendorInfo(vendorIndex).ChannelInfo(...
            obj.DeviceCode == deviceCodes &...
            obj.DeviceSerialNumber == [info.VendorInfo(vendorIndex).ChannelInfo.DeviceSerialNumber] &...
            obj.DeviceChannelIndex == [info.VendorInfo(vendorIndex).ChannelInfo.DeviceChannelIndex]);
        
        % Check for no match on the device.
        if isempty(channelInfo)
            % Warn the user of the load issue.
            warning(message('vnt:Channel:CannotReconnectToDevice'));
            % Return an empty version of the channel.
            obj = can.kvaser.Channel.empty();
            return;
        end
        
        try
            % Recreate the loaded channel to rebuild a connection
            % to the device.
            newObj = canChannel(...
                info.VendorInfo(vendorIndex).VendorName,...
                channelInfo.Device,...
                channelInfo.DeviceChannelIndex);
            
            % Set the database in the channel only if the database file
            % was loaded properly for use.
            if ~isempty(obj.Database) && obj.Database.Usable
                newObj.Database = obj.Database;
            else
                newObj.Database = [];
            end
            
            % Some properties should only be restored if the newly
            % reconstructed channel has initialization access for the
            % device to which it is connected.
            if newObj.InitializationAccess
                % Reset the previous bus speed in advanced form to
                % replace the exact timings.
                configBusSpeed(newObj,...
                    obj.BusSpeed,...
                    obj.SJW,...
                    obj.TSEG1,...
                    obj.TSEG2,...
                    obj.NumOfSamples);
                
                % Reset silent mode.
                newObj.SilentMode = obj.SilentMode;
            end
            
            % Restore the filters to their previous state by performing
            % each filter operation again. Note that due to changes made in
            % version 1.3 of this object, we no longer maintain forward or
            % backward compatibility to restore filter settings. Only 
            % 1.3 and great versions will have state restored on load.
            if obj.Version >= 1.3
                % Check the configured state and set the filters on the new
                % object accordingly for standard and extended filters.
                switch obj.FilterStateStandard.State
                    case 'Allow All'
                        newObj.filterAllowAll('Standard');
                    case 'Block All'
                        newObj.filterBlockAll('Standard');
                    case 'Allow Only'
                        newObj.filterAllowOnly(obj.FilterStateStandard.PassList, 'Standard');
                end
                    
                switch obj.FilterStateExtended.State
                    case 'Allow All'
                        newObj.filterAllowAll('Extended');
                    case 'Block All'
                        newObj.filterBlockAll('Extended');
                    case 'Allow Only'
                        newObj.filterAllowOnly(obj.FilterStateExtended.PassList, 'Extended');
                end
            end
            
            % Reset other properties to match the saved state.
            newObj.MessageReceivedFcn = obj.MessageReceivedFcn;
            newObj.MessageReceivedFcnCount = obj.MessageReceivedFcnCount;
            newObj.TransceiverState = obj.TransceiverState;
            
            % Load the UserData.
            if obj.Version >= 1.4
                newObj.UserData = obj.UserData;
            end
            
            % Load the InitialTimestamp.
            if obj.Version >= 1.5
                newObj.InitialTimestamp = obj.InitialTimestamp;
            end
            
            % Set the new channel to return from loading.
            obj = newObj;
            
        catch err %#ok<NASGU>
            % Warn the user of the load issue.
            warning(message('vnt:Channel:CannotReconfigureChannel'));
            % Return an empty version of the channel.
            obj = can.kvaser.Channel.empty();
            return;
        end
    end
    
end
        
end