gusucode.com > vnt工具箱matlab源码程序 > vnt/vnt/+j1939/TPTransmitter.m
classdef TPTransmitter < handle % TPTransmitter Implements a J1939 transport protocol transmission. % % This class implements a complete J1939 transport protocol % implementation for transmitting multiframe parameter groups. It can % handle both broadcast and peer-to-peer messaging with appropriate flow % control and timeouts. % Authors: Jaremy Pyle % Copyright 2015 The MathWorks, Inc. properties (SetAccess = 'private') % State - The current state of the multiframe tranfer. State % PGN - The parameter group number being transferred. PGN % SourceAddress - The node address of the transmitter of a % peer-to-peer multiframe transfer. SourceAddress % DestinationAddress - The node address of the receiver of a peer-to-peer % multiframe transfer. DestinationAddress % TotalPackets - The total number of data transfer packets required for % this multiframe sequence. TotalPackets % TotalSentPackets - The total number of unique packets sent for this % multiframe sequence. TotalSentPackets % PacketsToSend - The number of packets to be sent before any additional % flow control is required. PacketsToSend % NextPacket - The sequence number of the next packet to send. NextPacket % CMMessage - The Connection Management message to use to start the % multiframe sequence. CMMessage % DTMessages - An array of Data Transfer messages that comprise the % data transfer for the multiframe sequence. DTMessages % WaitTimeTic - A tic/toc timer used to manage timeout monitoring % within the multiframe sequence. WaitTimeTic % CANChannel - A CAN channel through which to transmit the multiframe % messages for this sequence. CANChannel end methods function obj = TPTransmitter(channel, pg) % TPTransmitter Class constructor. % Store the CAN channel to use for message transmit. obj.CANChannel = channel; % Store information from the parameter group to send. obj.PGN = pg.PGN; obj.DestinationAddress = pg.DestinationAddress; obj.SourceAddress = pg.SourceAddress; % Initialize the sequence numbering and transmission counter. obj.NextPacket = 1; obj.TotalSentPackets = 0; % Create multiframe CAN messages out of the parameter group. [obj.CMMessage, obj.DTMessages] = j1939.TPTransmitter.tpMakeMultiframeMessages(pg); % Store information about the quantity if data transfer messages. obj.PacketsToSend = numel(obj.DTMessages); obj.TotalPackets = numel(obj.DTMessages); % Set the initial state. obj.State = j1939.TPTxState.Inactive; end function transmitBAM(obj) % transmitBAM Transmit a multiframe broadcast parameter group. % % This method is used to send a multiframe sequence to broadcast % a parameter group to the entire network. It runs in blocking mode % until the transmission is complete with appropriate timing between % messages. % Send the CM message to start the TP sequence. obj.CANChannel.transmitRaw(obj.CMMessage); % Wait before starting the DT transmits. pause(j1939.Utility.TPDTTransmitDelay); % Send each of the TP DT message(s) individually. for ii = 1:obj.TotalPackets % Per protocol specification, we send the DT messages one % at a time with fixed delay between each message. obj.CANChannel.transmitRaw(obj.DTMessages(ii)); pause(j1939.Utility.TPDTTransmitDelay); end end function transmitP2P(obj) % transmitP2P Transmit a multiframe peer-to-peer parameter group. % % This method is used to send a multiframe sequence to direct a % parameter group to specific receiver. It runs in blocking mode % until the transmission is complete with appropriate timing between % messages. % Send the CM message to start the TP sequence. obj.CANChannel.transmitRaw(obj.CMMessage); % Prepare for a new TP peer-to-peer transmit sequence. obj.State = j1939.TPTxState.WaitingForCTS; obj.WaitTimeTic = tic; % Run the TP activity until the transfer is either complete, % aborted, or timed out. while obj.State ~= j1939.TPTxState.Completed && ... obj.State ~= j1939.TPTxState.Aborted && ... obj.State ~= j1939.TPTxState.TimedOut % Take action based on the current state. switch obj.State case j1939.TPTxState.SendingDT % Send a packet. obj.CANChannel.transmitRaw(obj.DTMessages(obj.NextPacket)); % Check if the last sent packet is a new transmission % or a retransmission. Receivers can force % retransmission via CTS messages. if obj.NextPacket > obj.TotalSentPackets % Increment the total sent count for a new packet. obj.TotalSentPackets = obj.TotalSentPackets + 1; end % Adjust details for next transmit. obj.NextPacket = obj.NextPacket + 1; obj.PacketsToSend = obj.PacketsToSend - 1; % Check if we are completely done sending. if obj.TotalPackets == obj.TotalSentPackets % If all packets are sent, wait for acknowledgement. obj.State = j1939.TPTxState.WaitingForAck; obj.WaitTimeTic = tic; % Check if we are done sending the last specified % sequence. elseif obj.PacketsToSend == 0 % If all specified packets since last CTS are sent, % then wait for continuation. obj.State = j1939.TPTxState.WaitingForCTS; obj.WaitTimeTic = tic; % There is more to send. else % Wait for a short period. pause(j1939.Utility.TPDTTransmitDelay); end case j1939.TPTxState.WaitingForCTS % Check for a T3 timeout. if toc(obj.WaitTimeTic) > j1939.Utility.TPTimeoutT3 obj.State = j1939.TPTxState.TimedOut; warning(message('vnt:J1939:TPTxTimeoutWaitingForCTS')); end case j1939.TPTxState.WaitingForAck % Check for a T3 timeout. if toc(obj.WaitTimeTic) > j1939.Utility.TPTimeoutT3 obj.State = j1939.TPTxState.TimedOut; warning(message('vnt:J1939:TPTxTimeoutWaitingForAck')); end case j1939.TPTxState.DTDelayed % Check for a T4 timeout. if toc(obj.WaitTimeTic) > j1939.Utility.TPTimeoutT4 obj.State = j1939.TPTxState.TimedOut; warning(message('vnt:J1939:TPTxTimeoutWaitingForDataTransferResume')); end end % Pause to allow other processing. pause(j1939.Utility.TPWaitTime); end end function processCTS(obj, message, sourceAddress, destinationAddress) % processCTS Process a Clear To Send TP CM message. % % This method is used to manage a Clear To Send message from the % destination of a peer-to-peer multiframe transfer. The Clear To % Send is used for flow control from the receiver, allowing it to % control the data output. % Check if the source and destination of this message % match the currently engaged TP sequence. if ~obj.isMatch(sourceAddress, destinationAddress) return; end % Get the needed information from the message. packetsToSend = message.Data(2); nextPacket = message.Data(3); % Take action based on the message details. if packetsToSend == 0 obj.PacketsToSend = packetsToSend; obj.State = j1939.TPTxState.DTDelayed; obj.WaitTimeTic = tic; else obj.PacketsToSend = packetsToSend; obj.NextPacket = nextPacket; obj.State = j1939.TPTxState.SendingDT; end end function processAck(obj, ~, sourceAddress, destinationAddress) % processAck Process an Acknowledgment TP CM message. % % This method is used to manage an Acknowledgment from the % destination of a peer-to-peer multiframe transfer. The % Acknowledgment message comes upon complete of reception of a data % by the receiver. % Check if the source and destination of this message % match the currently engaged TP sequence. if ~obj.isMatch(sourceAddress, destinationAddress) return; end % Log this transmission as complete. obj.State = j1939.TPTxState.Completed; end function processAbort(obj, msgRx, sourceAddress, destinationAddress) % processAbort Process an Abort TP CM message. % % This message is used to manage an Abort from the destination of a % peer-to-peer multiframe transfer. The Abort is used by the receiver % to cancel a multiframe transfer sequence. % Check if the source and destination of this message % match the currently engaged TP sequence. if ~obj.isMatch(sourceAddress, destinationAddress) return; end % Log this transmission as aborted. obj.State = j1939.TPTxState.Aborted; warning(message('vnt:J1939:TPTxAborted', msgRx.Data(2))); end function result = isMatch(obj, sourceAddress, destinationAddress) % isMatch Check if the provided address are for this TP sequence. % % This sequence is used to validate the destination and source % addresses provided as input to determine if they correspond to this % existing multiframe transfer. It returns a boolean state result. % Check if the source and destination of this CTS message % match the currently engaged TP sequence. Note that we have to % cross compare the input source against our intended destination % and the input destination against us being the source. We are % matching addresses of a message received by us as part of a % transport protocol flow control coming from our destination to us % as the source. if (destinationAddress ~= obj.SourceAddress) || (sourceAddress ~= obj.DestinationAddress) result = false; else result = true; end end function result = isBroadcast(obj) % isBroadcast Check if this TP sequence is broadcast or peer-to-peer. % % This method is used to check if the multiframe sequence represented % by this object is a broadcast or a peer-to-peer transfer. It % returns a boolean state result. % Return the status of this transmitter if it is a broadcast or % not. if obj.DestinationAddress == j1939.Utility.DestinationAll result = true; else result = false; end end end methods (Static) function [tpCMMessage, tpDTMessages] = tpMakeMultiframeMessages(pg) % tpMakeMultiframeMessages Create CAN messages for a multiframe transmit. % % This method is used to take a multiframe parameter group and create % CAN message structures that would be used to sent that parameter % group according to the J1939 transport protocol. It returns an % array of those CAN message structures. % Build the first message structure for the TP CM message. id = uint32(0); id = j1939.Utility.setPDUField('Priority', pg.Priority, id); id = j1939.Utility.setPDUField('PGN', j1939.Utility.TPConnectionManagementPGN, id); id = j1939.Utility.setPDUField('PDUSpecific', pg.DestinationAddress, id); id = j1939.Utility.setPDUField('SourceAddress', pg.SourceAddress, id); tpCMMessage.ID = id; tpCMMessage.Extended = true; tpCMMessage.Error = false; tpCMMessage.Remote = false; tpCMMessage.Timestamp = 0; % Set the special data for the TP CM message. if pg.DestinationAddress == j1939.Utility.DestinationAll tpCMMessage.Data(1) = j1939.Utility.TPBroadcastAnnounceControlByte; else tpCMMessage.Data(1) = j1939.Utility.TPRequestToSendControlByte; end length = uint16(numel(pg.Data)); bytes = typecast(length, 'uint8'); tpCMMessage.Data(2) = bytes(1); tpCMMessage.Data(3) = bytes(2); packets = uint8(ceil(numel(pg.Data)/7)); tpCMMessage.Data(4) = packets; tpCMMessage.Data(5) = j1939.Utility.FillByte; bytes = typecast(pg.PGN, 'uint8'); tpCMMessage.Data(6) = bytes(1); tpCMMessage.Data(7) = bytes(2); tpCMMessage.Data(8) = bytes(3); % Build the TP data transfer messages. tpDTMessages = tpCMMessage; id = j1939.Utility.setPDUField('PGN', j1939.Utility.TPDataTransferPGN, id); id = j1939.Utility.setPDUField('PDUSpecific', pg.DestinationAddress, id); % Load the large quantity data into the TP data transfer messages. nextData = 1; for ii = 1:packets tpDTMessages(ii).ID = id; tpDTMessages(ii).Extended = true; tpDTMessages(ii).Error = false; tpDTMessages(ii).Remote = false; tpDTMessages(ii).Timestamp = 0; % First byte is the sequence number. The rest are set to fill % bytes and overwritten with actual data. tpDTMessages(ii).Data = uint8([ii repmat(j1939.Utility.FillByte, 1, 7)]); % Write the actual data into the data transfer messages. for jj = 1:7 tpDTMessages(end).Data(jj+1) = pg.Data(nextData); nextData = nextData + 1; % Stop loading in data when all has been processed. if (ii == packets) && (nextData > length) break; end end end end end end