📄 j1939_16.c
字号:
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 + -