📄 j1939_dl.c
字号:
/**************************************************************************************
*
* 北京航空航大学 706教研室
* All rights reserved. 2005
*
*======================================================================================
*
* 文件名: J1939_DL.c
* 大纲: J1939协议栈
* 文件标识:
* 摘 要:
*
*======================================================================================
*
* 描述: 链路层文档
*
* 控制器: Freescale MC9s12H256
*
* 编译器: Metrowerks CodeWarrior IDE v5.2.1149
*
*======================================================================================
*
* 当前版本: 1.0.0
* 编程人员: 孙进
* 完成日期: 2006年2月
*
*======================================================================================
*
* 更新历史记录:
*
***************************************************************************************/
#include "J1939_includes.h"
#include "\driver\printp.h" //testbug
CAN_PACKET_T InBoundBuffer[IN_BUFFER_SIZE];
CAN_PACKET_T OutBoundBuffer[OUT_BUFFER_SIZE];
RING_T RingInBuffer;
RING_T RingOutBuffer;
U08 DL_state;
//==========================================================================================
//Datalink Modular Interfaces
//==========================================================================================
/****************************************************************************************
@函数名称 : void DL_init(void)
@参数 : None
@返回值 : None
@描述 : 初始化函数,设置 the datalink layer's packet buffers
和设置the datalink module into a "not primed" state
@作者 : 孙进
@最后编辑时间 : 2005-11-23
@版本 : V1.0.0
*****************************************************************************************/
void DL_init(void)
{
U08 i,j;
for(i=0;i<IN_BUFFER_SIZE;i++)
{
InBoundBuffer[i].byte_count = 0;
InBoundBuffer[i].identifier = 0;
for(j=0;j<CAN_MAX_BYTE_COUNT;j++)
{
InBoundBuffer[i].data[j] = 0;
}
}
for(i=0;i<OUT_BUFFER_SIZE;i++)
{
OutBoundBuffer[i].byte_count = 0;
OutBoundBuffer[i].identifier = 0;
for(j=0;j<CAN_MAX_BYTE_COUNT;j++)
{
OutBoundBuffer[i].data[j] = 0;
}
}
RingInBuffer.buffer = &InBoundBuffer[0];
RingInBuffer.head = 0;
RingInBuffer.tail = 0;
RingInBuffer.buffer_size = IN_BUFFER_SIZE - 1;
RingOutBuffer.buffer = &OutBoundBuffer[0];
RingOutBuffer.head = 0;
RingOutBuffer.tail = 0;
RingOutBuffer.buffer_size = OUT_BUFFER_SIZE - 1;
//设置链路层状态机
DL_state = NOTPRIMED;
return;
}
/****************************************************************************************
@函数名称 : void Rev_CANpkt( const CAN_PACKET_T* pkt_ptr )
@参数 : const CAN_PACKET_T* pkt_ptr
@返回值 : None
@描述 : 入栈接口函数在数据链路层和物理层之间。物理层调用在接收中断函数中调用
这个函数,当调用时函数把 CAN_PACKET_T 镜像拷贝到数据链路层入栈环形缓
冲区中
@作者 : 孙进
@最后编辑时间 : 2005-11-23
@版本 : V1.0.0
*****************************************************************************************/
#pragma CODE_SEG NON_BANKED
void Rev_CANpkt(const CAN_PACKET_T *pkt_ptr)
{
rng_enqueue(*pkt_ptr,&RingInBuffer);
return;
}
/****************************************************************************************
@函数名称 : void J1939_DL_periodic(void)
@参数 :
@返回值 :
@描述 : J1939周起函数,调用TICK。函数驱动数据链路层内部处理
@作者 : 孙进
@最后编辑时间 : 2005-11-23
@版本 : V1.0.0
*****************************************************************************************/
#pragma CODE_SEG NON_BANKED
void DL_periodic(void)
{
U08 m_DA,m_SA,m_PF,i;
U32 m_ID;
PGN_T m_PGN;
CAN_PACKET_T *rpkt_ptr;
CAN_PACKET_T *tpkt_ptr;
J1939_PDU_T pdu;
m_DA = 0;//初始化
m_SA = 0;
m_PF = 0;
m_ID = 0;
m_PGN = 0;
i = 0;
/*ringoutbuffer出队,报文发送*/
tpkt_ptr = rng_dequeue(&RingOutBuffer);
if(tpkt_ptr != NULL)
{
Trans_CANpkt(tpkt_ptr);
}
/*调用传输层函数,报文接收*/
while(TRUE)
{
rpkt_ptr = rng_dequeue(&RingInBuffer);
if(rpkt_ptr == NULL) //接收缓冲区空
{
break;
}
else
{
m_ID = rpkt_ptr->identifier;
m_SA = (U08)m_ID;
m_DA = (U08)(m_ID>>8);
m_PGN = (PGN_T)(m_ID>>8);
m_PF = (U08)(m_ID>>16);
if (m_PF < 240) //PDU1格式
{
if(m_DA==GLOBADDR)
{
//continue;
pdu.PGN = m_PGN & 0xFF00;
pdu.byte_count = rpkt_ptr->byte_count;
pdu.dest_addr = GLOBADDR;
pdu.source_addr = m_SA;
for(i=0;i<pdu.byte_count;i++)
{
pdu.data[i] = rpkt_ptr->data[i];
}
}
else if(m_DA==NODEADDR)
{
//continue;
pdu.PGN = m_PGN & 0xFF00;
pdu.byte_count = rpkt_ptr->byte_count;
pdu.dest_addr = m_DA;
pdu.source_addr = m_SA;
for(i=0;i<pdu.byte_count;i++)
{
pdu.data[i] = rpkt_ptr->data[i];
}
}
else
{
continue;
}
}
else //PDU2格式
{
pdu.PGN = m_PGN;
pdu.byte_count = rpkt_ptr->byte_count;
pdu.dest_addr = GLOBADDR;
pdu.source_addr = m_SA;
for(i=0;i<pdu.byte_count;i++)
{
pdu.data[i] = rpkt_ptr->data[i];
}
}
}
TL_process(&pdu);
}
return;
}
/****************************************************************************************
@函数名称 : const CAN_PACKET_T* Req_CANpkt(void)
@参数 : None
@返回值 : const CAN_PACKET_T
@描述 : 硬件抽象层在发送中断函数中调用这个函数获取新的数据帧
@作者 : 孙进
@最后编辑时间 : 2005-11-23
@版本 : V1.0.0
*****************************************************************************************/
const CAN_PACKET_T* Req_CANpkt(void)
{
CAN_PACKET_T *pkt_ptr;
pkt_ptr = rng_dequeue(&RingOutBuffer);
if (pkt_ptr == NULL)
{
DL_state = NOTPRIMED;
return NULL;
}
else
{
DL_state = PRIMED;
return pkt_ptr;
}
}
/****************************************************************************************
@函数名称 : void Build_CANpkt(J1939_TX_MESSAGE_T *msg_ptr, U08 tflag)
@参数 : None
@返回值 : J1939_TX_MESSAGE_T *msg_ptr, U08 tflag
@描述 : 传输层调用此函数将数据帧放入链路层发送缓冲区中
@作者 : 孙进
@最后编辑时间 : 2005-11-23
@版本 : V1.0.0
*****************************************************************************************/
void Build_CANpkt(J1939_TX_MESSAGE_T *msg_ptr,U08 tflag)
{
CAN_PACKET_T pkt_ptr;
U08 i;
if(tflag == 0)
{
pkt_ptr.byte_count = (U08)msg_ptr->byte_count;
pkt_ptr.identifier = msg_ptr->priority;
pkt_ptr.identifier = (pkt_ptr.identifier<<18) + msg_ptr->PGN;
if (msg_ptr->PGN < 0xF000)
{
pkt_ptr.identifier = pkt_ptr.identifier + msg_ptr->dest_addr;
}
pkt_ptr.identifier = (pkt_ptr.identifier<<8) + NODEADDR;
for(i=0;i<pkt_ptr.byte_count;i++)
{
pkt_ptr.data[i] = msg_ptr->data[i];
}
rng_enqueue(pkt_ptr,&RingOutBuffer);
//关中断
DL_state = PRIMED;
//开中断
}
else
{}
return;
}
/****************************************************************************************
@函数名称 : void rng_enqueue(CAN_PACKET_T msg, RING_T *ring)
@参数 : CAN_PACKET_T msg
RING_T *ring
@返回值 :
@描述 : 函数把CAN_PACKET_T msg加到RING_T *ring指向的结构的尾部
@作者 : 孙进
@最后编辑时间 : 2005-11-23
@版本 : V1.0.0
*****************************************************************************************/
#pragma CODE_SEG NON_BANKED
void rng_enqueue(CAN_PACKET_T msg, RING_T *ring)
{
if(((ring->tail+1)==ring->head)||((ring->tail==ring->buffer_size)&&(ring->head==0)))//环形队列满
{
return;
}
else
{
ring->buffer[ring->tail] = msg; //enqueue CAN message
ring->tail++;
if(ring->tail > ring->buffer_size) //wrap,CAN_BUF_MAX ->0
ring->tail = 0;
return;
}
}
/****************************************************************************************
@函数名称 : CAN_PACKET_T *rng_dequeue(RING_T *ring)
@参数 : RING_T *ring
@返回值 :
@描述 : 从ring中的头部取出一个CAN_PACKET_T,如果是空就返回NULL
@作者 : 孙进
@最后编辑时间 : 2005-11-23
@版本 : V1.0.0
*****************************************************************************************/
#pragma CODE_SEG NON_BANKED
CAN_PACKET_T *rng_dequeue(RING_T *ring)
{
CAN_PACKET_T *temp;
if(ring->head == ring->tail)
{
return NULL; //ring buffer is empty
}
else
{
temp = &ring->buffer[ring->head];
ring->head++;
if(ring->head > ring->buffer_size)
ring->head = 0; //wrap,CAN_BUF_MAX ->0
return temp;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -