基本信息
源码名称:OSEK_NM-master汽车网络管理源码
源码大小:0.67M
文件格式:.zip
开发语言:C/C++
更新时间:2019-12-24
   友情提示:(无需注册或充值,赞助后即可获取资源下载链接)

     嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300

本次赞助数额为: 2 元 
   源码介绍

基于OsekNM 2.5.3协议实现的OsekNM,跨平台的结构,目前只实现了STM32F407ZGT6平台的驱动。
1. 目录结构
1.1 App目录是一个keil5工程,App/keil/Objects/OsekNM.hex是一个可以直接在STM32F407ZGT6平台运    行的hex文件。
1.2 Driver目录包含了stm32f407子目录和Win7子目录,stm32f407目录下就是实现的STM32F407ZGT6平台的底层驱动,包括定时器和CAN模块的驱动,以及Stm32标准库的东西;Win7子目录是在windows7平台下执行的一些文件;Driver_Common.c是一些公用的驱动,由OsekNM_core统一调用。

1.3 OsekNM_core实现了OsekNM 2.5.3协议的核心逻辑,OsekNM.c实现了对各个节点各状态的处理,OsekNMServer.c实现了OsekNM 2.5.3协议提供给应用程序的API。

2. 移植
2.1 在Driver目录新建文件夹,保存新平台的驱动程序,新的平台下需要实现CAN模块和定时器及中断的驱动程序。
2.2 修改Driver_Common.c文件,修改TX_CAN_Transmit()函数,调用新平台发送CAN报文的CAN模块驱动程序,修改InitPlatform()函数,调用新平台初始化CAN模块和定时器的函数;Recv_EveryMessage()被CAN接受报文中断服务函数调用。
2.3 修改Driver_Common.h文件,#define 新的平台,并包含驱动相关的头文件,#define NMID 新的网络管理报文ID,#define ADDR_SELF 新的节点源地址。
2.4 可以参考stm32f407的例子来实现自己平台的移植。

3. 附注
整个代码移植到我的开发板,并且在CANoe平台验证过。
专门在Vspy平台实现了虚拟的网络管理节点

#include "Driver_Common.h"

//与平台相关的公用的驱动代码在这里实现,包括NM报文缓冲区、定时器

//定时器设置
static char SetAlarm_TTYP = 0;
static char SetAlarm_TMAX = 0;
static char SetAlarm_TERROR = 0;
static char SetAlarm_TWBS = 0;
//定时器计数器
static int TTYP_Count = 0;
static int TMAX_Count = 0;
static int TERROR_Count = 0;
static int TWBS_Count = 0;
//报文缓冲区定义
static RecvFIFO_t RecvFIFO;

//定时器超时标志
static TimerOutFlag_t TimerOutFlag_TTYP = 0;
static TimerOutFlag_t TimerOutFlag_TMAX = 0;
static TimerOutFlag_t TimerOutFlag_TERROR = 0;
static TimerOutFlag_t TimerOutFlag_TWBS = 0;

//节点当前状态
extern NMStateType_t NMCurrentState;
//节点当前子状态
extern NMStateType_t NMCurrentSubState;
//节点上一个状态
extern NMStateType_t  NMPreState;
extern NMNodeCfg_t NodeCfg;
//DEBUG
//#define DRVCOM_DEBUG
#ifdef DRVCOM_DEBUG
#define DRVCOM_PRINT(...) printf(__VA_ARGS__)
#else 
#define DRVCOM_PRINT(...)
#endif

/*函数名:TX_CAN_Transmit
*参数:NMPDU
*返回值:成功 1
*说明:调用平台相关的报文发送函数
*/
NMTypeU8_t TX_CAN_Transmit(NMPDU_t* NMPDU)
{
	/*发送报文到总线*/
	#ifdef STM32F407
	return STM32_TX_CAN_Transmit(NMPDU);
	#endif
}

//NMPDU初始化,保留位置1
void InitNMPDU(NMPDU_t* NMPDU)
{
	int i = 0;
	NMPDU->MsgCtl = 0xc8;
	//NMPDU->MsgID = ((NMID << 8) | ADDR_SELF);
	//NMPDU->MsgDA = ADDR_SELF;

	for (; i < 6; i  )
	{
		NMPDU->MsgData[i] = 0xff;
	}
}

//返回定时器是否超时,-1 失败
TimerOutFlag_t GetTimerIsOut(NMTimerType_t TimerType)
{
	switch (TimerType)
	{
	case NM_TIMER_TTYP:
		return TimerOutFlag_TTYP;
	case NM_TIMER_TMAX:
		return TimerOutFlag_TMAX;
	case NM_TIMER_TERROR:
		return TimerOutFlag_TERROR;
	case NM_TIMER_TWBS:
		return TimerOutFlag_TWBS;
	}
	return -1;
}

//清除定时器超时标志
void ClcTimerOutFlag(NMTimerType_t TimerType)
{
	switch (TimerType)
	{
	case NM_TIMER_TTYP:
		TimerOutFlag_TTYP = 0;
		break;
	case NM_TIMER_TMAX:
		TimerOutFlag_TMAX = 0;
		break;
	case NM_TIMER_TERROR:
		TimerOutFlag_TERROR = 0;
		break;
	case NM_TIMER_TWBS:
		TimerOutFlag_TWBS = 0;
		break;
	}
}


//FIFO相关的函数
/*说明:SetFIFO,将收到的报文放入FIFO,并调整FIFO
* 参数:GenericMessage* msg,报文指针
* 返回值:1:成功放入报文到FIFO,0:放入失败
*/
char SetToFIFO(NMPDU_t* msg)
{
	if (RecvFIFO.FullFlag == 1)//先判断缓冲区满否
		return 0;
	/*放入报文到缓冲区*/
	RecvFIFO.MSGs[RecvFIFO.Tail% FIFOMAX] = *msg;
	RecvFIFO.Tail = (RecvFIFO.Tail   1) % FIFOMAX;
	/*清除空标识*/
	RecvFIFO.EmptyFlag = 0;
	if ((RecvFIFO.Tail   1) == RecvFIFO.Head)//缓冲区满
		RecvFIFO.FullFlag = 1;
	return 1;
}
/*说明:GetFIFO,从FIFO取出报文,并调整FIFO
* 参数:GenericMessage* msg,报文指针
* 返回值:1:成功取出报文,0:取出失败
*/
char GetFromFIFO(NMPDU_t* msg)
{
	int i = 2;
	if (RecvFIFO.EmptyFlag == 1)//先判断缓冲区空否
		return 0;
	/*从缓冲区取出报文*/
	msg->MsgDA = RecvFIFO.MSGs[RecvFIFO.Head% FIFOMAX].MsgDA;
	msg->MsgCtl = RecvFIFO.MSGs[RecvFIFO.Head% FIFOMAX].MsgCtl;
	msg->MsgID = RecvFIFO.MSGs[RecvFIFO.Head% FIFOMAX].MsgID;
	//数据域直接复制
	for (; i < OSEKNM_DLC; i  )
	{
		msg->MsgData[i] = RecvFIFO.MSGs[RecvFIFO.Head% FIFOMAX].MsgData[i];
	}
	RecvFIFO.Head = (RecvFIFO.Head   1) % FIFOMAX;
	/*清除满标识*/
	RecvFIFO.FullFlag = 0;
	if ((RecvFIFO.Tail) == RecvFIFO.Head)//缓冲区空
		RecvFIFO.EmptyFlag = 1;
	return 1;
}
/*说明:ClearFIFO,清空整个FIFO
* 参数:void
* 返回值:void
*/
void ClearFIFO(void)
{
	RecvFIFO.Total = 0;
	RecvFIFO.Head = 0;
	RecvFIFO.Tail = 0;
	RecvFIFO.FullFlag = 0;
	RecvFIFO.EmptyFlag = 1;
}

//定时器超时函数
/*LimpHome定时器*/
static void TimerOutTERROR()
{
	TimerOutFlag_TERROR = 1;
#ifdef PRINT_LOG
	char buf[100];
	sprintf(buf, "TError out State:%d\n", NMCurrentState);
	LogOutPut(buf);
#endif
}

/*TMax超时定时器*/
static void TimerOutTMAX()
{
	TimerOutFlag_TMAX = 1;
#ifdef PRINT_LOG
	char buf[100];
	sprintf(buf, "TMAX out State:%d\n", NMCurrentState);
	LogOutPut(buf);
#endif
}

/*TTYP定时器*/
static void TimerOutTTYP()
{
	TimerOutFlag_TTYP = 1;
#ifdef PRINT_LOG
	char buf[100];
	sprintf(buf, "TTYP out State:%d\n", NMCurrentState);
	LogOutPut(buf);
#endif
}
/*WaitBusSleep定时器*/
static void TimerOutTWBS()
{
	TimerOutFlag_TWBS = 1;
#ifdef PRINT_LOG
	char buf[100];
	sprintf(buf, "TWBS out State:%d\n", NMCurrentState);
	LogOutPut(buf);
#endif
}

//10ms定时器
void Timer10()
{
	/*调用SetAlarm(xx),定时器开始递增*/
	if (SetAlarm_TTYP)
	{
		TTYP_Count  ;

		if (TTYP_Count >= 10)//TTYP=100ms
		{
			TTYP_Count = 0;//重新计数
			TimerOutTTYP();
			SetAlarm_TTYP = 0;//每次用完定时器都将其关闭,从而简化定时器管理
		}
	}
	else {
		TTYP_Count = 0;
	}
	if (SetAlarm_TMAX)
	{
		TMAX_Count  ;
		if (TMAX_Count >= 26)//TMAX=260ms
		{
			TMAX_Count = 0;//重新计数
			TimerOutTMAX();
			SetAlarm_TMAX = 0;//每次用完定时器都将其关闭
		}
	}
	else {
		TMAX_Count = 0;
	}
	if (SetAlarm_TERROR)
	{
		TERROR_Count  ;
		if (TERROR_Count >= 100)//TError=1000ms
		{
			TERROR_Count = 0;//重新计数
			TimerOutTERROR();
			SetAlarm_TERROR = 0;//每次用完定时器都将其关闭
		}
	}
	else {
		TERROR_Count = 0;
	}
	if (SetAlarm_TWBS)
	{
		TWBS_Count  ;
		if (TWBS_Count >= 500)//TError=5000ms
		{
			TWBS_Count = 0;//重新计数
			TimerOutTWBS();
			SetAlarm_TWBS = 0;//每次用完定时器都将其关闭
		}
	}
	else {
		TWBS_Count = 0;
	}
}

//平台相关的初始化
void InitPlatform()
{
	/*缓冲区初始化*/
	RecvFIFO.GetMsg = GetFromFIFO;
	RecvFIFO.SetMsg = SetToFIFO;
	RecvFIFO.ClearBuff = ClearFIFO;
	RecvFIFO.ClearBuff();
	/*1.STM32相关的初始化*/
	#ifdef STM32F407
	/*定时器初始化*/
	Stm32Timer3Init();//10ms中断一次
	/*CAN模块初始化*/
	STM32_CAN1_Init();
	#endif
}


/*
*自定义定时器函数:SetAlarm
参数:定时器类型
说明:每次调用都使定时器重新从0开始
*返回值:定时器ID,用定时器类型ID代替定时器ID
*/
int SetAlarm(NMTimerType_t timer)
{
	int Tid = 0;
	switch (timer)
	{
	case NM_TIMER_TTYP:
		SetAlarm_TTYP = 1;
		TTYP_Count = 0;
		TimerOutFlag_TTYP = 0;//每次设置定时器前先清除标志位
		Tid = NM_TIMER_TTYP;
		break;
	case NM_TIMER_TMAX:
		TMAX_Count = 0;
		SetAlarm_TMAX = 1;
		TimerOutFlag_TMAX = 0;//每次设置定时器前先清除标志位
		Tid = NM_TIMER_TMAX;
		break;
	case NM_TIMER_TERROR:
		TERROR_Count = 0;
		SetAlarm_TERROR = 1;
		TimerOutFlag_TERROR = 0;//每次设置定时器前先清除标志位
		Tid = NM_TIMER_TERROR;
		break;
	case NM_TIMER_TWBS:
		TWBS_Count = 0;
		SetAlarm_TWBS = 1;
		TimerOutFlag_TWBS = 0;//每次设置定时器前先清除标志位
		Tid = NM_TIMER_TWBS;
		break;
	}
	return Tid;
}
/*
*自定义定时器函数:CancelAlarm
参数:定时器类型
说明:定时器清0,不再计数
*/
void CancelAlarm(NMTimerType_t timer)
{
	switch (timer)
	{
	case NM_TIMER_TTYP:
		TTYP_Count = 0;
		SetAlarm_TTYP = 0;
		TimerOutFlag_TTYP = 0;//每次关闭定时器先清除标志位
		break;
	case NM_TIMER_TMAX:
		TMAX_Count = 0;
		SetAlarm_TMAX = 0;
		TimerOutFlag_TMAX = 0;//每次关闭定时器先清除标志位
		break;
	case NM_TIMER_TERROR:
		TERROR_Count = 0;
		SetAlarm_TERROR = 0;
		TimerOutFlag_TERROR = 0;//每次关闭定时器先清除标志位
		break;
	case NM_TIMER_TWBS:
		TWBS_Count = 0;
		SetAlarm_TWBS = 0;
		TimerOutFlag_TWBS = 0;//每次关闭定时器先清除标志位
		break;
	}
}
/*CAN中断收到的报文*/
void Recv_EveryMessage(NMPDU_t* p_Msg)
{
	/*将所有收到的NM报文放入缓冲区FIFO*/
	if (((p_Msg->MsgID) != NMID) && ((p_Msg->MsgID>>8) == (NMID>>8)))//过滤网络报文,不接收自己发出去的
	{
		RecvFIFO.SetMsg(p_Msg);//暂时不处理返回值
	}
}