📄 j1939_16.c
字号:
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_Send );
#else
WriteSPI( MCP_Send );
#endif
UNSELECT_MCP;
#ifndef J1939_POLL_MCP
// Clear the transmit interrupt flag
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_BITMOD );
WRITESPI( MCP_CANINTF );
WRITESPI( MCP_Send<<2 );
WRITESPI( 0 );
#else
WriteSPI( MCP_BITMOD );
WriteSPI( MCP_CANINTF );
WriteSPI( MCP_Send<<2 );
WriteSPI( 0 );
#endif
UNSELECT_MCP;
#endif
// Put back PDUFormat the way it was in case somebody reuses the message.
// MsgPtr->Msg.PDUFormat = oldSIDL;
}
/*********************************************************************
J1939_AddressClaimHandling
This routine is called either when the CA must claim its address on
the bus or another CA is trying to claim the same address on the bus and
we must either defend ourself or relinquish the address. If the CA has
an address in the proprietary range of 0-127 or 248-253, it can take
the address immediately.
Parameters: unsigned char ADDRESS_CLAIM_RX indicates an Address
Claim message has been received and this
CA must either defend or give up its
address.
ADDRESS_CLAIM_TX indicates that the CA is
initiating a claim to its address.
Return: None
*********************************************************************/
#ifndef J1939_POLL_MCP
#pragma interrupt_level 0
#endif
void J1939_AddressClaimHandling( unsigned char Mode )
{
// Get most of the message ready here, since it'll be very similar
// for both messages to be sent. Note that J1939_PF_ADDRESS_CLAIMED
// is the same value as J1939_PF_CANNOT_CLAIM_ADDRESS. We can't copy
// the data yet because we might need to look at the old data.
OneMessage.Msg.Priority = J1939_CONTROL_PRIORITY;
OneMessage.Msg.PDUFormat = J1939_PF_ADDRESS_CLAIMED;
OneMessage.Msg.DestinationAddress = J1939_GLOBAL_ADDRESS;
OneMessage.Msg.DataLength = J1939_DATA_LENGTH;
if (Mode == ADDRESS_CLAIM_TX)
goto SendAddressClaim;
if (OneMessage.Msg.SourceAddress != J1939_Address)
return;
if (CompareName( OneMessage.Msg.Data ) != -1) // Our CA_Name is not less
{
// Send Cannot Claim Address message
CopyName();
OneMessage.Msg.SourceAddress = J1939_NULL_ADDRESS;
SendOneMessage( (J1939_TX_QUEUE_BANK J1939_MESSAGE *) &OneMessage );
// Set up MCP filter 2 to receive messages sent to the global address
SetAddressFilter( J1939_GLOBAL_ADDRESS );
J1939_Flags.Flags.CannotClaimAddress = 1;
J1939_Flags.Flags.WaitingForAddressClaimContention = 0;
return;
}
SendAddressClaim:
// Send Address Claim message for CommandedAddress
CopyName();
OneMessage.Msg.SourceAddress = CommandedAddress;
SendOneMessage( (J1939_TX_QUEUE_BANK J1939_MESSAGE *) &OneMessage );
if (((CommandedAddress & 0x80) == 0) || // Addresses 0-127
((CommandedAddress & 0xF8) == 0xF8)) // Addresses 248-253 (254,255 illegal)
{
J1939_Flags.Flags.CannotClaimAddress = 0;
J1939_Address = CommandedAddress;
// Set up MCP filter 2 to receive messages sent to this address
SetAddressFilter( J1939_Address );
}
else
{
// We don't have a proprietary address, so we need to wait.
J1939_Flags.Flags.WaitingForAddressClaimContention = 1;
ContentionWaitTime = 0;
}
}
/*********************************************************************
J1939_DequeueMessage
This routine takes a message from the receive queue and places it in
the caller's buffer. If there is no message to return, an appropriate
return code is returned.
Parameters: J1939_MESSAGE * Pointer to the caller's message buffer
Return: RC_SUCCESS Message dequeued successfully
RC_QUEUEEMPTY No messages to return
RC_CANNOTRECEIVE System cannot currently receive
messages. This will be returned only
after the receive queue is empty.
*********************************************************************/
unsigned char J1939_DequeueMessage( J1939_USER_MSG_BANK J1939_MESSAGE *MsgPtr )
{
unsigned char rc = RC_SUCCESS;
#ifndef J1939_POLL_MCP
INTE = 0;
#endif
if (RXQueueCount == 0)
{
if (J1939_Flags.Flags.CannotClaimAddress)
rc = RC_CANNOTRECEIVE;
else
rc = RC_QUEUEEMPTY;
}
else
{
*MsgPtr = RXQueue[RXHead];
RXHead ++;
if (RXHead >= J1939_RX_QUEUE_SIZE)
RXHead = 0;
RXQueueCount --;
}
#ifndef J1939_POLL_MCP
INTE = 1;
#endif
return rc;
}
/*********************************************************************
J1939_EnqueueMessage
This routine takes a message from the caller's buffer and places it in
the transmit queue. If the message cannot be queued or sent, an appropriate
return code is returned. If interrupts are being used, then the
transmit interrupt is enabled after the message is queued.
Parameters: J1939_MESSAGE * Pointer to the caller's message buffer
Return: RC_SUCCESS Message dequeued successfully
RC_QUEUEFULL Transmit queue full; message not queued
RC_CANNOTTRANSMIT System cannot currently transmit
messages.
*********************************************************************/
unsigned char J1939_EnqueueMessage( J1939_USER_MSG_BANK J1939_MESSAGE *MsgPtr )
{
unsigned char rc = RC_SUCCESS;
#ifndef J1939_POLL_MCP
INTE = 0;
#endif
if (J1939_Flags.Flags.CannotClaimAddress)
rc = RC_CANNOTTRANSMIT;
else
{
if ((TXQueueCount < J1939_TX_QUEUE_SIZE) ||
(J1939_OVERWRITE_TX_QUEUE == J1939_TRUE))
{
if (TXQueueCount < J1939_TX_QUEUE_SIZE)
{
TXQueueCount ++;
TXTail ++;
if (TXTail >= J1939_TX_QUEUE_SIZE)
TXTail = 0;
}
TXQueue[TXTail] = *MsgPtr;
#ifndef J1939_POLL_MCP
// Enable the transmit interrupts on TXB0 and TXB1
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_BITMOD );
WRITESPI( MCP_CANINTE );
WRITESPI( MCP_TX_INT );
WRITESPI( MCP_TX01_INT );
#else
WriteSPI( MCP_BITMOD );
WriteSPI( MCP_CANINTE );
WriteSPI( MCP_TX_INT );
WriteSPI( MCP_TX01_INT );
#endif
UNSELECT_MCP;
#endif
}
else
rc = RC_QUEUEFULL;
}
#ifndef J1939_POLL_MCP
INTE = 1;
#endif
return rc;
}
/*********************************************************************
J1939_Initialization
This routine is called on system initialization. It initializes
global variables, microcontroller peripherals and interrupts, and the
MCP2515. It then starts the process of claiming the CA's address.
NOTE: This routine will NOT enable global interrupts. The CA needs
to do that when it's ready.
Parameters: None
Return: None
*********************************************************************/
#pragma inline J1939_Initialization
void J1939_Initialization( void )
{
unsigned char i;
// unsigned char j;
// Initialize global variables;
J1939_Flags.FlagVal = 1; // Cannot Claim Address, all other flags cleared.
ContentionWaitTime = 0;
CommandedAddress = J1939_Address = J1939_STARTING_ADDRESS;
TXHead = 0;
TXTail = 0xFF;
TXQueueCount = 0;
RXHead = 0;
RXTail = 0xFF;
RXQueueCount = 0;
CA_Name[7] = J1939_CA_NAME7;
CA_Name[6] = J1939_CA_NAME6;
CA_Name[5] = J1939_CA_NAME5;
CA_Name[4] = J1939_CA_NAME4;
CA_Name[3] = J1939_CA_NAME3;
CA_Name[2] = J1939_CA_NAME2;
CA_Name[1] = J1939_CA_NAME1;
CA_Name[0] = J1939_CA_NAME0;
// Initialize the SPI peripheral.
CloseSPI();
OpenSPI( J1939_SPI_SPEED, J1939_SPI_MODE, J1939_SAMPLE );
// Initialize the chip select pin
J1939_CS_TRIS = 0;
J1939_CS_PIN = 1;
// Initialize the MCP2515 and put it into configuration mode automatically.
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_RESET );
#else
WriteSPI( MCP_RESET );
#endif
UNSELECT_MCP;
// Wait for the MCP to start up
for (i=0; i<128; i++ );
// Set up the MCP receive buffer 0 mask to receive broadcast messages.
// Set up receive buffer 1 mask to receive messages sent to the
// global address (or eventually us). Set up bit timing as defined by
// the CA, and set up interrupts on either receive buffer full.
MCP_Write( MCP_RXM0SIDH, 0x07 ); // RXM0SIDH
MCP_Write( MCP_RXM0SIDL, 0x80 ); // RXM0SIDL
MCP_Write( MCP_RXM1EID8, 0xFF ); // RXM1EID8
MCP_Write( MCP_CNF3, J1939_CNF3 ); // CNF3
MCP_Write( MCP_CNF2, J1939_CNF2 ); // CNF2
MCP_Write( MCP_CNF1, J1939_CNF1 ); // CNF1
// Set all the RXB0 filters to accept only broadcast messages
// (PF = 240-255). Set all the RXB1 filters to accept only the
// global address. Once we get an address for the CA, we'll change
// filter 2 to accept that address.
MCP_Write( MCP_RXF0SIDH, 0x07 ); // RXF0SIDH
MCP_Write( MCP_RXF0SIDL, 0x88 ); // RXF0SIDL
MCP_Write( MCP_RXF1SIDH, 0x07 ); // RXF1SIDH
MCP_Write( MCP_RXF1SIDL, 0x88 ); // RXF1SIDL
MCP_Write( MCP_RXF2SIDL, 0x08 ); // RXF2SIDL
MCP_Write( MCP_RXF2EID8, J1939_GLOBAL_ADDRESS ); // RXF2EID8
MCP_Write( MCP_RXF3SIDL, 0x08 ); // RXF3SIDL
MCP_Write( MCP_RXF3EID8, J1939_GLOBAL_ADDRESS ); // RXF3EID8
MCP_Write( MCP_RXF4SIDL, 0x08 ); // RXF4SIDL
MCP_Write( MCP_RXF4EID8, J1939_GLOBAL_ADDRESS ); // RXF4EID8
MCP_Write( MCP_RXF5SIDL, 0x08 ); // RXF5SIDL
MCP_Write( MCP_RXF5EID8, J1939_GLOBAL_ADDRESS ); // RXF5EID8
// Put the MCP2515 into Normal Mode
MCP_Write( MCP_CANCTRL, MODE_NORMAL + J1939_CLKOUT + J1939_CLKOUT_PS );
// Clear out and deactivate the transmit and receive buffers.
/*
for (i = 0; i < 3; i++)
{
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_WRITE );
WRITESPI( MCP_TXB0CTRL + i*16 );
for (j = 0; j < 14; j++)
WRITESPI( 0x00 );
#else
WriteSPI( MCP_WRITE );
WriteSPI( MCP_TXB0CTRL + i*16 );
for (j = 0; j < 14; j++)
WriteSPI( 0x00 );
#endif
UNSELECT_MCP;
}
*/
// Enable the MCP interrupt. The caller must enable global
// interrupts when ready.
#ifndef J1939_POLL_MCP
TRISB0 = 1; // Set RB0 as an input.
INTEDG = 0; // Interrupt on falling edge of RB0/INT pin
INTE = 1; // Enable the RB0/INT interrupt.
MCP_Write( MCP_CANINTE, MCP_RX_INT );
#endif
// Start the process of claiming our address
J1939_AddressClaimHandling( ADDRESS_CLAIM_TX );
}
/*********************************************************************
J1939_ISR
This function is called by the CA if it gets an interrupt and the INTF
flag is set. First we'll clear the interrupt flag. Then we'll call
the receive and transmit functions to process any received messages and
to transmit any messages in the transmit queue.
Parameters: None
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -