1.5wuling_zhuanjietou/HARDWARE/CAN/can_app.c
2024-10-17 09:06:51 +08:00

512 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************** (C) COPYRIGHT 2011 嵌入式开发工作室 ********************
* 文件名 can_app.c
* 描述
*
* 版本 V1.0
**********************************************************************************/
#include "Sys.h"
#include "adc.h"
#include "can.h"
#include "CanBusDrv.h"
#include "candrvctrl.h"
static st_cl candrv_if[2];
/*****************************************************************************
* 记录每一个CAN ID的发送时间
****************************************************************************/
static struct
{
unsigned int frame_id; /* ID */
unsigned int period; /* 发送周期 */
unsigned int send_tick; /* 发送TICK */
unsigned int sent_tick; /* 发送成功TICK */
} CAN_ID_SENT_TICK_MAP[] =
{
{CANBMS65CINFOID_WULING, 1000, 0, 0},
{CANBMS38AINFOID_WULING, 100, 0, 0},
{CANBMS38BINFOID_WULING, 100, 0, 0},
{CANBMS38CINFOID_WULING, 100, 0, 0},
{CANBMS38DINFOID_WULING, 100, 0, 0},
{CANBMS38EINFOID_WULING, 100, 0, 0},
{CANBMS598INFOID_WULING, 1000, 0, 0},
{CANBMS599INFOID_WULING, 1000, 0, 0},
{CANBMS59AINFOID_WULING, 1000, 0, 0},
};
void can2_bus_error_cb(e_link_sts err);
/****************************************************************************
* @brief: 检测can ID的实际发送时间是否超过指定时间
*
* @param frame_id: 要检测的CAN ID,
* @param outtime: 超时时间单位ms
*
* @return: bool
* true: 周期超时
* false: 未达到超时时间
*/
bool can_sent_cycle_timeout(unsigned int frame_id)
{
unsigned short i;
for (i=0; i < (sizeof(CAN_ID_SENT_TICK_MAP)/sizeof(CAN_ID_SENT_TICK_MAP[0])); i++)
{
if (CAN_ID_SENT_TICK_MAP[i].frame_id == frame_id)
{
if ( CAN_ID_SENT_TICK_MAP[i].sent_tick == 0)
{
return true;
}
// if (CAN_ID_SENT_TICK_MAP[i].send_tick == 0 || CAN_ID_SENT_TICK_MAP[i].sent_tick == 0)
// {
// return true;
// }
#if 0
else if (abs(CAN_ID_SENT_TICK_MAP[i].sent_tick - CAN_ID_SENT_TICK_MAP[i].send_tick) < 5)
{
/* 发送时间和发送成功时间相近,则表示肯定上一次发送成功了,用发送时间进行对比 */
if (TickOut(&CAN_ID_SENT_TICK_MAP[i].send_tick, CAN_ID_SENT_TICK_MAP[i].period))
{
return true;
}
else
{
return false;
}
}
#endif
else if (TickOut(&CAN_ID_SENT_TICK_MAP[i].sent_tick, CAN_ID_SENT_TICK_MAP[i].period - 3))
{
/* 发送时间和发送成功时间不相近,则表示肯定上一次发送失败了,用上一次发送成功时间进行对比 */
return true;
}
else
{
return false;
}
}
}
return true;
}
/****************************************************************************
* @brief: 记录每一个CANid的发送成功的时间
*
* @param frame_id: 发送成功CAN ID
*
* @return: void
*/
static __inline void can_sent_tick_update(unsigned int frame_id)
{
unsigned short i;
for (i=0; i < (sizeof(CAN_ID_SENT_TICK_MAP)/sizeof(CAN_ID_SENT_TICK_MAP[0])); i++)
{
if (CAN_ID_SENT_TICK_MAP[i].frame_id == frame_id)
{
TickOut(&CAN_ID_SENT_TICK_MAP[i].sent_tick, 0);
}
}
}
/****************************************************************************
* @brief: 记录每一个CANid的发送的时间
*
* @param frame_id: 发送成功CAN ID
*
* @return: void
*/
static __inline void can_send_tick_update(unsigned int frame_id)
{
unsigned short i;
for (i=0; i < (sizeof(CAN_ID_SENT_TICK_MAP)/sizeof(CAN_ID_SENT_TICK_MAP[0])); i++)
{
if (CAN_ID_SENT_TICK_MAP[i].frame_id == frame_id)
{
TickOut(&CAN_ID_SENT_TICK_MAP[i].send_tick, 0);
}
}
}
/*can 包 发送*/
int8_t can_write( CanTxMsg *TxMessage)
{
u16 time_up = 0;
if (candrv_if[0].SEND != NULL)
{
return candrv_if[0].SEND(0, (TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId, \
TxMessage->Data, (TxMessage->RTR == CAN_RTR_DATA)?TxMessage->DLC:0, \
(TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId,NULL);
}
return 0;
}
int8_t can_write2( CanTxMsg *TxMessage)
{
u16 time_up = 0;
uint8_t TransmitMailbox;
static u16 sendpoweronflag = 0;
static u8 sendlowvoltflag = 0;
static u8 sendhighvoltflag = 0;
#if 1
if(sendpoweronflag++ < 12) //刚上电不判断输入电压
{
}
else
{
if(sendpoweronflag > 100)sendpoweronflag =100;
if(sendlowvoltflag == 0)
{
if (Sample_DataS.VIN_Input_Voltage < 5.90) {
sendlowvoltflag = 1;
return 1;
}
}
else
{
if (Sample_DataS.VIN_Input_Voltage < 6.40) {
return 1;
}
else
{
sendlowvoltflag = 0;
}
}
if(sendhighvoltflag == 0)
{
if (Sample_DataS.VIN_Input_Voltage > 18.1) {
sendhighvoltflag = 1;
return 1;
}
}
else
{
if (Sample_DataS.VIN_Input_Voltage > 17.6) {
return 1;
}
else
{
sendhighvoltflag = 0;
}
}
}
#endif
//UDS禁止发送
if (!UdsApi_Is_UdsEnableNCMTx()) {
return 1;
}
if (candrv_if[1].SEND != NULL)
{
if (candrv_if[1].SEND(1, (TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId, \
TxMessage->Data, (TxMessage->RTR == CAN_RTR_DATA)?TxMessage->DLC:0, \
(TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId, NULL))
{
/* 暂时不需要更新 */
//can_send_tick_update((TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId);
return 0;
}
}
return 0;
}
/************************************************************************************************************
* 总线异常BUSSOFF的处理
***********************************************************************************************************/
typedef enum
{
E_BUS_NORMAL = 0,
E_BUS_BUSOFF,
E_BUS_RECOVERY_ACK,
} bus_recovery_step_e;
typedef struct
{
unsigned char step; /* 0 - 正常 1 - bus off 延时 2-bus off recovery 确认 */
unsigned int bus_off_tick; /* 触发bus off的时间 */
unsigned int recovery_tick; /* recovery的时间 */
unsigned short recovery_times; /* 连续recovey次数 */
unsigned char first_frm;
} bus_off_recovery_t;
static const unsigned short BUS_OFF_TIME_MS[] = {30, 198, 198, 198, 198, 198};
static bus_off_recovery_t canbus[BSP_CAN_CHANNEL_NUM];
/**
* @brief: 处理bus off的recovery操作
*
* @param : void
*
* @return: void
*
* @remark: 自动恢复总线可放在定时器或在循环内其被执行的间隔不能超过10ms。
*/
#include "led.h"
extern void WULING_DCDCSendBms2_force(void);
extern u8 EntSlpFlag ;
void can_bus_off_recovery(void)
{
unsigned char i;
unsigned int timeout;
unsigned char buffer[8]={0};
for (i = 0; i < BSP_CAN_CHANNEL_NUM; i++)
{
// if ((canbus[i].step == E_BUS_BUSOFF) && (EntSlpFlag==0)/* && 非休眠条件*/)
if ((canbus[i].step == E_BUS_BUSOFF)/* && 非休眠条件*/)
{
if (canbus[i].recovery_times < (sizeof(BUS_OFF_TIME_MS)/sizeof(BUS_OFF_TIME_MS[0])))
{
timeout = BUS_OFF_TIME_MS[canbus[i].recovery_times];
}
else
{
/* reopen 超过指定次数则使用设定的最后一个间隔 */
timeout = BUS_OFF_TIME_MS[(sizeof(BUS_OFF_TIME_MS)/sizeof(BUS_OFF_TIME_MS[0]))-1];
}
if (TickOut(&canbus[i].bus_off_tick, timeout))
{
SYS_ENTER_CRITICAL();
canbus[i].recovery_times++;
if (candrv_if[i].ConfigBus != NULL) candrv_if[i].ConfigBus(i, 0,0,0);
canbus[i].step = E_BUS_RECOVERY_ACK;
// /* 模拟发送网络管理数据包 */
// if(ChkPwrManageAccoff()!=0 )
// {
buffer[0]=1;
// }
if (candrv_if[i].SEND!= NULL) candrv_if[i].SEND(i, CANBMS65CINFOID_WULING, buffer, 8, CANBMS65CINFOID_WULING, NULL);
SYS_EXIT_CRITICAL();
TickOut(&canbus[i].recovery_tick, 0);
canbus[i].first_frm = 1;
}
}
else if (canbus[i].step == E_BUS_RECOVERY_ACK)
{
if (TickOut(&canbus[i].recovery_tick, 103))
{
WULING_DCDCSendBms2_force();
canbus[i].recovery_times = 0;
canbus[i].step = E_BUS_NORMAL;
}
}
}
}
/**
* @brief: 打印 can 总线状态
*/
void can_bus_off_status_printf(void)
{
printf("can 1: step(%d), recorvery(%d), last bus off tick(%d), last recovery tick(%d)!\n", \
canbus[0].step, canbus[0].recovery_times, canbus[0].bus_off_tick, canbus[0].recovery_tick);
printf("can 2: step(%d), recorvery(%d), last bus off tick(%d) last recovery tick(%d)!\n", \
canbus[1].step, canbus[1].recovery_times, canbus[1].bus_off_tick, canbus[1].recovery_tick);
}
/***********************************************************************************************
* 以下是应用层针对总线底层的接口
**********************************************************************************************/
void can2_bus_error_cb(e_link_sts err)
{
if (err != e_err_bussoff)
{
/* 不是BUSS OFF暂时不处理 */
return;
}
if (canbus[1].step != E_BUS_BUSOFF)
{
if (candrv_if[1].CloseLink != NULL) candrv_if[1].CloseLink(1);
canbus[1].step = E_BUS_BUSOFF;
TickOut(&canbus[1].bus_off_tick, 0);
}
}
static void can2_comm_sent_cb(unsigned int canid, unsigned int result)
{
/* 发送回调 */
if (result == _SUCCESS)
{
/* 发送成功 */
can_sent_tick_update(canid);
if (canbus[1].first_frm > 0 && canbus[1].step == E_BUS_RECOVERY_ACK)
{
canbus[1].first_frm = 0;
TickOut(&canbus[1].recovery_tick, 0);
}
}
else if (result == _ABANDON)
{
/* 因为异常恢复 */
}
else
{
/* 发送失败 */
}
}
static st_pl can2_protocol =
{
"整车协议",
0,
3,
10,
NULL,
can2_bus_error_cb,
can2_comm_sent_cb
};
#if 0
static void can1_bus_error_cb(e_link_sts err)
{
}
static void can1_comm_sent_cb(unsigned int canid, unsigned int result)
{
/* 发送回调 */
}
#endif
static st_pl can1_protocol =
{
"整车协议",
0,
3,
10,
NULL,
NULL,
NULL
};
void InitCanDrvCtrlMode(void);
void InitCanifToCanDrvCtrl(void);
bool InstallProtocalToIF(unsigned char chan, st_pl* ppl, st_cl * pcl);
/**
* @brief: 初始化can 协议的基础功能
*/
void can_porting_init(void);
/**
* @brief: 初始化can 协议的基础功能的调度
*/
void can_porting_schedule(void);
void app_can_handle(void)
{
static uint8_t bms_rev_busy_flag = 0;
static CanRxMsg MutliBMSCAN1Msg;
CanRxMsg rec_message;
unsigned int id;
unsigned char data[8], len;
can_porting_schedule();
while (candrv_if[0].REC != NULL && candrv_if[0].REC(0,&id, data, &len) == true)
{
/* 数据接收 */
CAN_FRAME_INIT((CanTxMsg *)(&rec_message), id, data, len);
rec_message.FMI = 0;
bms_rev_busy_flag = 1;
if(bms_RcvCanSingleDataProc(rec_message) == 1)
{
MutliBMSCAN1Msg = rec_message;
bms_RcvCanMutliData(MutliBMSCAN1Msg,0,&bms_rev_busy_flag);
}
IWDG_Feed();
}
while (candrv_if[1].REC != NULL && candrv_if[1].REC(1,&id, data, &len) == true)
{
/* 数据接收 */
CAN_FRAME_INIT((CanTxMsg *)(&rec_message), id, data, len);
rec_message.FMI = 0;
//UDS允许接收
if (UdsApi_Is_UdsEnableNCMRx()) {
bms_RcvCan2DataProc(rec_message);
}
UdsApi_MsgQueueIn(rec_message);
memset(&rec_message,0,sizeof(rec_message));
// bms_RcvCan2DataProc(rec_message);
IWDG_Feed();
}
can_bus_off_recovery();
}
void app_can_init(void)
{
memset(&canbus[0], 0x00, sizeof(canbus));
memset(&candrv_if[0], 0x00, sizeof(candrv_if));
can_porting_init();
InitCanDrvCtrlMode();
InitCanifToCanDrvCtrl();
if(InstallProtocalToIF(0,&can1_protocol,&candrv_if[0]) == true)
{
printf("can1 协议初始化成功\r\n");
}
if(InstallProtocalToIF(1,&can2_protocol,&candrv_if[1]) == true)
{
printf("can2 协议初始化成功\r\n");
}
if (candrv_if[0].ConfigBus != NULL)
{
candrv_if[0].ConfigBus(0, 0, 0, 0);
}
if (candrv_if[1].ConfigBus != NULL)
{
candrv_if[1].ConfigBus(1, 0, 0, 0);
}
}