⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 j1939_16.c

📁 CAN控制器2515的J1939库源程序
💻 C
📖 第 1 页 / 共 3 页
字号:
Return:		None
*********************************************************************/
#ifndef J1939_POLL_MCP
#pragma interrupt_level 0
#pragma inline J1939_ISR
void J1939_ISR( void )
{
	INTF = 0;

	J1939_ReceiveMessages();
	J1939_TransmitMessages();
}
#endif

/*********************************************************************
J1939_Poll

If we're polling for messages, then this routine should be called by
the CA every few milliseconds during CA processing.  The routine receives
any messages that are waiting and transmits any messages that are queued.
Then we see if we are waiting for an address contention response.  If
we are and we've timed out, we accept the address as ours.

If the CA is using interrupts, then this routine should be called by
the CA every few milliseconds while the WaitingForAddressClaimContention
flag is set after calling J1939_Initialization.  If the Commanded Address
message can be accepted, this routine must also be called every few
milliseconds during CA processing in case we are commanded to change our
address.  If using interrupts, this routine will not check for received
or transmit messages; it will only check for a timeout on address
claim contention.

Parameters:	unsigned char	The number of milliseconds that have
							passed since the last time this routine was
							called.  This number can be approximate,
							and to meet spec, should be rounded down.
Return:		None
*********************************************************************/
void J1939_Poll( unsigned char ElapsedTime )
{
	unsigned int	Temp;

	// Update the Contention Wait Time.  We have to do that before
	// we call J1939_ReceiveMessages in case the time gets reset back
	// to zero in that routine.

	Temp = ContentionWaitTime + ElapsedTime;
	if (Temp > 255)
		Temp = 255;
	ContentionWaitTime = (unsigned char) Temp;

	#ifdef J1939_POLL_MCP
		J1939_ReceiveMessages();
		J1939_TransmitMessages();
	#endif

	if (J1939_Flags.Flags.WaitingForAddressClaimContention &&
		(ContentionWaitTime >= 250))
	{
		J1939_Flags.Flags.CannotClaimAddress = 0;
		J1939_Flags.Flags.WaitingForAddressClaimContention = 0;
		J1939_Address = CommandedAddress;

		// Set up MCP filter 2 to receive messages sent to this address.
		// If we're using interrupts, make sure that interrupts are disabled
		// around this section, since it will mess up what we're doing.
		#ifndef J1939_POLL_MCP
			INTE = 0;
		#endif
		SetAddressFilter( J1939_Address );
		#ifndef J1939_POLL_MCP
			INTE = 1;
		#endif
	}
}

/*********************************************************************
J1939_ReceiveMessage

This routine is called either when an interrupt is received from the
MCP2515 or by polling.  If a message has been received, it is read in.
If it is a network management message, it is processed.  Otherwise, it
is placed in the receive queue for the user.  Note that interrupts are
disabled during this routine, since it is called from the interrupt handler.


NOTE: To save stack space, the function J1939_CommandedAddressHandling
was brought inline.

Parameters:	None
Return:		None
*********************************************************************/

void J1939_ReceiveMessages( void )
{
	unsigned char	Status;
	unsigned char	Mask = MCP_RX0IF;
	unsigned char	Loop;

	SELECT_MCP;
	#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
		WRITESPI( MCP_READ_STATUS );
		READSPI( Status );
	#else
		WriteSPI( MCP_READ_STATUS );
		Status = ReadSPI();
	#endif
	UNSELECT_MCP;

	Status &= (MCP_RX0IF | MCP_RX1IF);
	while (Status != 0)
	{
		if (Status & Mask)
		{
			// Read a message from the receive buffer
			SELECT_MCP;
			#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
				if (Mask == MCP_RX0IF)
					WRITESPI( MCP_READ_RX0 )
				else
					WRITESPI( MCP_READ_RX1 )
				for (Loop=0; Loop<J1939_MSG_LENGTH; Loop++)
					READSPI( OneMessage.Array[Loop] );
				if (OneMessage.Msg.DataLength > 8)
					OneMessage.Msg.DataLength = 8;
				for (Loop=0; Loop<OneMessage.Msg.DataLength; Loop++)
					READSPI( OneMessage.Msg.Data[Loop] );
			#else
				if (Mask == MCP_RX0IF)
					WriteSPI( MCP_READ_RX0 );
				else
					WriteSPI( MCP_READ_RX1 );
				for (Loop=0; Loop<J1939_MSG_LENGTH; Loop++)
					OneMessage.Array[Loop] = ReadSPI();
				if (OneMessage.Msg.DataLength > 8)
					OneMessage.Msg.DataLength = 8;
				for (Loop=0; Loop<OneMessage.Msg.DataLength; Loop++)
					OneMessage.Msg.Data[Loop] = ReadSPI();
			#endif
			UNSELECT_MCP;

			// Clear the receive flag, regardless of using polling or interrupts
			SELECT_MCP;
			#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
				WRITESPI( MCP_BITMOD );
				WRITESPI( MCP_CANINTF );
				WRITESPI( Mask );
				WRITESPI( 0 );
			#else
				WriteSPI( MCP_BITMOD );
				WriteSPI( MCP_CANINTF );
				WriteSPI( Mask );
				WriteSPI( 0 );
			#endif
			UNSELECT_MCP;

			// Format the PDU Format portion so it's easier to work with.
			Loop = (OneMessage.Msg.PDUFormat & 0xE0) >> 3;			// Get SID2-0 ready.
			OneMessage.Msg.PDUFormat = (OneMessage.Msg.PDUFormat & 0x03) |
										Loop |
										((OneMessage.Msg.PDUFormat_Top & 0x07) << 5);

			switch( OneMessage.Msg.PDUFormat )
			{
#ifdef J1939_ACCEPT_CMDADD
				case J1939_PF_CM_BAM:
					if ((OneMessage.Msg.Data[0] == J1939_BAM_CONTROL_BYTE) &&
						(OneMessage.Msg.Data[5] == J1939_PGN0_COMMANDED_ADDRESS) &&
						(OneMessage.Msg.Data[6] == J1939_PGN1_COMMANDED_ADDRESS) &&
						(OneMessage.Msg.Data[7] == J1939_PGN2_COMMANDED_ADDRESS))
					{
						J1939_Flags.Flags.GettingCommandedAddress = 1;
						CommandedAddressSource = OneMessage.Msg.SourceAddress;
					}
					break;
				case J1939_PF_DT:
					if ((J1939_Flags.Flags.GettingCommandedAddress == 1) &&
						(CommandedAddressSource == OneMessage.Msg.SourceAddress))
					{	// Commanded Address Handling
						if ((!J1939_Flags.Flags.GotFirstDataPacket) &&
							(OneMessage.Msg.Data[0] == 1))
						{
							for (Loop=0; Loop<7; Loop++)
								CommandedAddressName[Loop] = OneMessage.Msg.Data[Loop+1];
							J1939_Flags.Flags.GotFirstDataPacket = 1;
						}
						else if ((J1939_Flags.Flags.GotFirstDataPacket) &&
							(OneMessage.Msg.Data[0] == 2))
						{
							CommandedAddressName[7] = OneMessage.Msg.Data[1];
							CommandedAddress = OneMessage.Msg.Data[2];
							if ((CompareName( CommandedAddressName ) == 0) &&	// Make sure the message is for us.
								CA_AcceptCommandedAddress())					// and we can change the address.
								J1939_AddressClaimHandling( ADDRESS_CLAIM_TX );
							J1939_Flags.Flags.GotFirstDataPacket = 0;
							J1939_Flags.Flags.GettingCommandedAddress = 0;
						}
						else	// This really shouldn't happen, but just so we don't drop the data packet
							goto PutInReceiveQueue;
					}
					else
						goto PutInReceiveQueue;
					break;
#endif
			case J1939_PF_REQUEST:
				if ((OneMessage.Msg.Data[0] == J1939_PGN0_REQ_ADDRESS_CLAIM) &&
					(OneMessage.Msg.Data[1] == J1939_PGN1_REQ_ADDRESS_CLAIM) &&
					(OneMessage.Msg.Data[2] == J1939_PGN2_REQ_ADDRESS_CLAIM))
					J1939_RequestForAddressClaimHandling();
				else
					goto PutInReceiveQueue;
				break;
				case J1939_PF_ADDRESS_CLAIMED:
					J1939_AddressClaimHandling( ADDRESS_CLAIM_RX );
					break;
				default:
PutInReceiveQueue:
					if ((RXQueueCount < J1939_RX_QUEUE_SIZE) ||
						(J1939_OVERWRITE_RX_QUEUE == J1939_TRUE))
					{
						if (RXQueueCount < J1939_RX_QUEUE_SIZE)
						{
							RXQueueCount ++;
							RXTail ++;
							if (RXTail >= J1939_RX_QUEUE_SIZE)
								RXTail = 0;
						}
						RXQueue[RXTail] = OneMessage;
					}
					else
						J1939_Flags.Flags.ReceivedMessagesDropped = 1;
			}
		}
		Status &= ~Mask;
		Mask = MCP_RX1IF;
	}
}

/*********************************************************************
J1939_RequestForAddressClaimHandling

This routine is called if we're received a Request for Address Claim
message.  If we cannot claim an address, we send out a Cannot Claim
Address message.  Otherwise, we send out an Address Claim message for
our address.

NOTE:	J1939_PF_CANNOT_CLAIM_ADDRESS is the same value as
		J1939_PF_ADDRESS_CLAIMED, so we can reduce code size by
		combining the two.  Only the source address changes between
		the two messages.
*********************************************************************/
void J1939_RequestForAddressClaimHandling( void )
{
	if (J1939_Flags.Flags.CannotClaimAddress)
		OneMessage.Msg.SourceAddress = J1939_NULL_ADDRESS;	// Send Cannot Claim Address message
	else
		OneMessage.Msg.SourceAddress = J1939_Address;		// Send Address Claim for current address

	OneMessage.Msg.Priority = J1939_CONTROL_PRIORITY;
	OneMessage.Msg.PDUFormat = J1939_PF_ADDRESS_CLAIMED;	// Same as J1939_PF_CANNOT_CLAIM_ADDRESS
	OneMessage.Msg.DestinationAddress = J1939_GLOBAL_ADDRESS;
	OneMessage.Msg.DataLength = J1939_DATA_LENGTH;
	CopyName();
	SendOneMessage( (J1939_TX_QUEUE_BANK J1939_MESSAGE *) &OneMessage );
}

/*********************************************************************
J1939_TransmitMessages

This routine transmits as many messages from the transmit queue as it
can.  If the system cannot transmit messages, an error code is returned.
Note that interrupts are disabled during this routine, since it is
called from the interrupt handler.

Parameters:	None
Return:		RC_SUCCESS			Message was transmitted successfully
			RC_CANNOTTRANSMIT	System cannot transmit messages.
								Either we cannot claim an address or
								the MCP2515 is busy.
			RC_QUEUEEMPTY		Transmit queue was empty
*********************************************************************/
unsigned char J1939_TransmitMessages( void )
{
	unsigned char Mask = 0x04;
	unsigned char Status;

	if (TXQueueCount != 0)
	{
		if (J1939_Flags.Flags.CannotClaimAddress)
			return RC_CANNOTTRANSMIT;

		SELECT_MCP;
		#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
			WRITESPI( MCP_READ_STATUS );
			READSPI( Status );
			Status &= MCP_TX01_MASK;				// Save only the transmit request flags.
		#else
			WriteSPI( MCP_READ_STATUS );
			Status = ReadSPI() & MCP_TX01_MASK;		// Save only the transmit request flags.
		#endif
		UNSELECT_MCP;

		if (Status == MCP_TX01_MASK)			// All transmit buffers are busy
			return RC_CANNOTTRANSMIT;

		while ((TXQueueCount > 0) && (Mask != 0))
		{
			if ((Status & Mask) == 0)	// This buffer is free
			{
				TXQueue[TXHead].Msg.SourceAddress = J1939_Address;
				SendOneMessage( (J1939_TX_QUEUE_BANK J1939_MESSAGE *) &(TXQueue[TXHead]) );
				TXHead ++;
				if (TXHead >= J1939_TX_QUEUE_SIZE)
					TXHead = 0;
				TXQueueCount --;
			}
			Mask <<= 2;
		}

		#ifndef J1939_POLL_MCP
			// Disable the transmit interrupt if the queue is empty
			if (TXQueueCount == 0)
			{
				SELECT_MCP;
				#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
					WRITESPI( MCP_BITMOD );
					WRITESPI( MCP_CANINTE );
					WRITESPI( MCP_TX_INT );
					WRITESPI( MCP_NO_INT );
				#else
					WriteSPI( MCP_BITMOD );
					WriteSPI( MCP_CANINTE );
					WriteSPI( MCP_TX_INT );
					WriteSPI( MCP_NO_INT );
				#endif
				UNSELECT_MCP;
			}
		#endif

		return RC_SUCCESS;
	}
	return RC_QUEUEEMPTY;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -