can控制器 uds诊断完整代码(c写的keil项目)遵循iso sae J1939标准(stm32 N32 系列MCU可用)
Single Frame(SF)- 单帧;First Frame (FF)-第一帧;Consecutive Frame (CF)-连续帧;Flow Control (FC)-流控帧;N_PDU type-网络层协议控制单元类型;N_PCI-网络层协议控制信息;SF_DL-单帧 数据长度;FF_DL-首帧数据长度;SN-连续帧序列号;FS-流控状态;BS-块大小;STmin-连续帧最小时间间隔。
UDS(Unified Diagnostic Services,统一诊断服务)是一种用于汽车行业的标准化诊断协议,基于CAN总线进行通信。UDS服务是诊断服务的规范化标准,规定了读取DTC(故障码)的指令、读诊断数据流的指令等。它允许维修人员使用诊断设备通过CAN总线与汽车电子控制单元(ECU)进行通信,执行各种诊断任务,如读取故障码、控制ECU的功能、以及更新ECU的软件等。
整个项目完整代码已经在前装车载设备上使用:
/***************************************************************************//**
\author
\mail
\version 0.03 - CANoe Test Passed
\date 2024-09-24
\description uds network code, base on ISO 15765
*******************************************************************************/
#include "network_layer_private.h"
#include "network_layer.h"
#include "uds_api.h"
/*******************************************************************************
Type Definition
*******************************************************************************/
/*******************************************************************************
Global Varaibles
*******************************************************************************/
static network_layer_st nwl_st = NWL_IDLE;
static bool_t g_wait_cf = FALSE;
static bool_t g_wait_fc = FALSE;
static uint32_t nt_timer[TIMER_CNT] = {0};
static uint8_t g_rfc_stmin = 0; /* received flowcontrol SeparationTime */
static uint8_t g_rfc_bs = 0; /* received flowcontrol block size */
static uint8_t g_xcf_bc = 0; /* transmit consecutive frame block counter */
static uint8_t g_xcf_sn = 0; /* transmit consecutive frame SequenceNumber */
static uint8_t g_rcf_bc = 0; /* received frame block counter */
static uint8_t g_rcf_sn = 0; /* received consecutive frame SequenceNumber */
/* transmit buffer */
static uint8_t remain_buf[UDS_FF_DL_MAX];
static uint16_t remain_len = 0;
static uint16_t remain_pos = 0;
/* recieve buffer */
static uint8_t recv_buf[UDS_FF_DL_MAX];
static uint16_t recv_len = 0;
static uint16_t recv_fdl = 0; /* frame data len */
//OS_EVENT *UdsMutex;
/*******************************************************************************
Function declaration
*******************************************************************************/
static void
send_flowcontrol (uint8_t flow_st);
//static indication_func uds_indication = NULL;
//static confirm_func uds_confirm = NULL;
static nt_usdata_t N_USData = {NULL, NULL, NULL};
/*******************************************************************************
Function Definition - common
*******************************************************************************/
/**
* nt_timer_start - start network timer
*
* void :
*
* returns:
* void
*/
static void
nt_timer_start (uint8_t num)
{
if (num >= TIMER_CNT) return;
if (num == TIMER_N_CR)
nt_timer[TIMER_N_CR] = TIMEOUT_N_CR;
if (num == TIMER_N_BS)
nt_timer[TIMER_N_BS] = TIMEOUT_N_BS;
if (num == TIMER_STmin)
nt_timer[TIMER_STmin] = g_rfc_stmin;
}
static void
nt_timer_start_wv (uint8_t num, uint32_t value)
{
if (num >= TIMER_CNT) return;
if (num == TIMER_N_CR)
nt_timer[TIMER_N_CR] = value;
if (num == TIMER_N_BS)
nt_timer[TIMER_N_BS] = value;
if (num == TIMER_STmin)
nt_timer[TIMER_STmin] = value;
}
static void
nt_timer_stop (uint8_t num)
{
if (num >= TIMER_CNT) return;
nt_timer[num] = 0;
}
/**
* nt_timer_run - run a network timer, should be invoked per 1ms
*
* void :
*
* returns:
* 0 - timer is not running, 1 - timer is running, -1 - a timeout occur
*/
static int
nt_timer_run (uint8_t num)
{
if (num >= TIMER_CNT) return 0;
if (nt_timer[num] == 0)
{
return 0;
}
else if (nt_timer[num] == 1)
{
nt_timer[num] = 0;
return -1;
}
else
{
/* if (nt_timer[num] > 1) */
nt_timer[num]--;
return 1;
}
}
/**
* nt_timer_chk - check a network timer and stop it
*
* num :
*
* returns:
* 0 - timer is not running, 1 - timer is running,
*/
static int
nt_timer_chk (uint8_t num)
{
if (num >= TIMER_CNT) return 0;
if (nt_timer[num] > 0)
{
nt_timer[num] = 0; /* stop timer */
return 1;
}
else
{
nt_timer[num] = 0; /* stop timer */
return 0;
}
}
/**
* clear_network - clear network status
*
* void :
*
* returns:
* void
*/
static void
clear_network (void)
{
uint8_t num;
nwl_st = NWL_IDLE;
g_wait_cf = FALSE;
g_wait_fc = FALSE;
g_xcf_bc = 0;
g_xcf_sn = 0;
g_rcf_bc = 0;
g_rcf_sn = 0;
for (num = 0; num < TIMER_CNT; num++)
nt_timer_stop (num);
}
/*******************************************************************************
Function Definition - recieve
*******************************************************************************/
/**
* recv_singleframe - recieved a single frame from CAN
*
* @frame_buf : uds can frame data buffer
* @frame_dlc : uds can frame length
*
* returns:
* void
*/
static void
recv_singleframe (uint8_t frame_buf[], uint8_t frame_dlc)
{
uint16_t i, uds_dlc;
// uint8_t service_id;
uds_dlc = NT_GET_SF_DL (frame_buf[0]);
// service_id = frame_buf[1];
/************************************/
#ifdef UDS_CAN_ID_STD
if (uds_dlc > 7 || uds_dlc == 0)
return;
#else
if (uds_dlc > 6 || uds_dlc == 0)
return;
#endif
recv_fdl = uds_dlc;
for (i = 0; i < frame_dlc - 1; i++)
recv_buf[i] = frame_buf[1+i];
recv_len = frame_dlc - 1;
N_USData.indication (recv_buf, recv_fdl, N_OK);
}
/**
* recv_firstframe - recieved a firt frame from CAN
*
* service : L_Data.indication (FF)
* @frame_buf : uds can frame data buffer
* @frame_dlc : uds can frame length
*
* returns:
* 0 - recv a right frame, other - err
*/
static int
recv_firstframe (uint8_t frame_buf[], uint8_t frame_dlc)
{
uint16_t i;
// uint8_t service_id;
uint16_t uds_dlc;
uds_dlc = ((uint16_t)(frame_buf[0]&0x0f)) << 8;
uds_dlc |= frame_buf[1];
// service_id = frame_buf[2];
/************************************/
#ifdef UDS_CAN_ID_STD
if (uds_dlc < 8)
return -1;
#else
if (uds_dlc < 7)
return -1;
#endif
/**
* if FF_DL is greater than the available receiver buffer size
* abort the message reception and send
* an FC N_PDU with Overflow.
*/
if (uds_dlc >= UDS_FF_DL_MAX) {
send_flowcontrol (FS_OVFLW);
return -2;
}
recv_fdl = uds_dlc;
for (i = 0; i < frame_dlc - 2; i++)
recv_buf[i] = frame_buf[2+i];
recv_len = frame_dlc - 2;
/**
* after received first frame,
* send flowcontrol frame and wait consecutive frame,
*/
send_flowcontrol (FS_CTS);
g_rcf_bc = 0;
g_wait_cf = TRUE;
nt_timer_start(TIMER_N_CR);
/* claer the consecutive frane0 sn */
g_rcf_sn = 0;
N_USData.ffindication (uds_dlc);
return 1;
}
/**
* recv_consecutiveframe - recieved a consecutive frame from CAN
*
* service: L_Data.indication (CF)
* @frame_buf : uds can frame data buffer
* @frame_dlc : uds can frame length
*
* returns:
* 0 - recv end, 1 - recv continue, other - err
*/
static int
recv_consecutiveframe (uint8_t frame_buf[], uint8_t frame_dlc)
{
uint8_t cf_sn;
uint16_t i;
cf_sn = NT_GET_CF_SN (frame_buf[0]);
/* if N_Cr timeout, Abort message transmission and issue N_TIMEOUT_Cr */
if(nt_timer_chk (TIMER_N_CR) <= 0) return -1;
g_rcf_sn++;
if (g_rcf_sn > 0x0f)
g_rcf_sn = 0;
if (g_rcf_sn != cf_sn) {
N_USData.indication (recv_buf, recv_len, N_WRONG_SN);
return -2;
}
for(i = 0; i < UDS_CF_DL_COM; i++)
{
recv_buf[recv_len+i] = frame_buf[1+i];
}
recv_len += UDS_CF_DL_COM;
if (recv_len >= recv_fdl)
{
g_wait_cf = FALSE;
N_USData.indication (recv_buf, recv_fdl, N_OK);
return 0;
}
else
{
if (NT_XMIT_FC_BS > 0)
{
g_rcf_bc++;
if (g_rcf_bc >= NT_XMIT_FC_BS)
{
/**
* after NT_XMIT_FC_BS consecutive frames,
* send flowcontrol frame and wait consecutive frame,
*/
send_flowcontrol (FS_CTS);
g_rcf_bc = 0;
}
}
g_wait_cf = TRUE;
nt_timer_start(TIMER_N_CR);
return 1;
}
}
/**
* recv_flowcontrolframe - process uds flowc control frame
*
* service: L_Data.indication (FC)
* @frame_buf : uds can frame data buffer
* @frame_dlc : uds can frame length
*
* returns:
* 0 - recv CTS, 1 - recv WT, other - err
*/
static int
recv_flowcontrolframe (uint8_t frame_buf[], uint8_t frame_dlc)
{
uint8_t fc_fs;
fc_fs = NT_GET_FC_FS (frame_buf[0]);
/**
* if N_Bs timeout,
* Abort message transmission and issue N_TIMEOUT_Bs,
* if not timeout, stop the timer.
*/
if(nt_timer_chk (TIMER_N_BS) <= 0) return -1;
/**
* Got from CANoe Test:
* After the First frame is received the Tester sends a functional
* adressed Flow control. ECU must abort sending of the response
*/
//if (g_tatype == N_TATYPE_FUNCTIONAL) return -1;
g_wait_fc = FALSE;
if (fc_fs >= FS_RESERVED) {
N_USData.confirm (N_INVALID_FS);
return -2;
}
if (fc_fs == FS_OVFLW) {
N_USData.confirm (N_BUFFER_OVFLW);
return -3;
}
if (fc_fs == FS_WT) {
g_wait_fc = TRUE;
nt_timer_start (TIMER_N_BS);
return 1;
}
/**
* get the fc block size and stmin
*/
g_rfc_bs = frame_buf[1];
if (frame_buf[2] <= 0x7f)
g_rfc_stmin = frame_buf[2]+1;
else
g_rfc_stmin = 0x7f; /* 127 ms */
/* start to transmit consecutive frame */
g_xcf_bc = 0;
nt_timer_start_wv (TIMER_STmin, 1);
return 0;
}
/*******************************************************************************
Function Definition - send
*******************************************************************************/
/**
* send_flowcontrol - send flowcontrol frame
*
* service: L_Data.confirm (FC)
* @flow_st : flow status
*
* returns:
* void
*/
static void
send_flowcontrol (uint8_t flow_st)
{
uint8_t send_buf[UDS_VALID_FRAME_LEN] = {0};
memset(send_buf, 0xcc, UDS_VALID_FRAME_LEN);
send_buf[0] = NT_SET_PCI_TYPE_FC (flow_st);
send_buf[1] = NT_XMIT_FC_BS;
send_buf[2] = NT_XMIT_FC_STMIN;
ZTai_UDS_Send (send_buf, UDS_VALID_FRAME_LEN);
}
/**
* send_singleframe - send a single frame msg
*
* @msg_buf : uds msg data buffer
* @msg_dlc : uds msg length
*
* returns:
* void
*/
static void
send_singleframe (uint8_t msg_buf[], uint16_t msg_dlc)
{
uint16_t i;
uint8_t send_buf[UDS_VALID_FRAME_LEN] = {0};
memset(send_buf, 0xcc, UDS_VALID_FRAME_LEN);
if (msg_dlc == 0 || msg_dlc > UDS_SF_DL_MAX) return;
send_buf[0] = NT_SET_PCI_TYPE_SF ((uint8_t)msg_dlc);
for (i = 0; i < msg_dlc; i++)
send_buf[1+i] = msg_buf[i];
ZTai_UDS_Send (send_buf, UDS_VALID_FRAME_LEN);
}
/**
* send_firstframe - send a first frame data
*
* service : L_Data.confirm (FF)
* @msg_buf : uds msg data buffer
* @msg_dlc : uds msg length
*
* returns:
* int
*/
static int
send_firstframe (uint8_t msg_buf[], uint16_t msg_dlc)
{
uint16_t i;
uint8_t send_buf[UDS_VALID_FRAME_LEN] = {0};
memset(send_buf, 0xcc, UDS_VALID_FRAME_LEN);
if (msg_dlc < UDS_FF_DL_MIN || msg_dlc > UDS_FF_DL_MAX) return 0;
send_buf[0] = NT_SET_PCI_TYPE_FF ((uint8_t)(msg_dlc >> 8));
send_buf[1] = (uint8_t)(msg_dlc & 0x00ff);
for (i = 0; i < UDS_VALID_FRAME_LEN-2; i++)
send_buf[2+i] = msg_buf[i];
ZTai_UDS_Send (send_buf, UDS_VALID_FRAME_LEN);
/**
* start N_Bs and wait for a fc.
*/
g_wait_fc = TRUE;
nt_timer_start (TIMER_N_BS);
return UDS_VALID_FRAME_LEN-2;
}
/**
* send_consecutiveframe - send consecutive frame data
*
* service : L_Data.confirm (CF)
* @msg_buf : uds msg data buffer
* @msg_dlc : uds msg length
*
* returns:
* int
*/
static int
send_consecutiveframe (uint8_t msg_buf[], uint16_t msg_dlc, uint8_t frame_sn)
{
uint16_t i;
uint8_t send_buf[UDS_VALID_FRAME_LEN] = {0};
memset(send_buf, 0xcc, UDS_VALID_FRAME_LEN);
send_buf[0] = NT_SET_PCI_TYPE_CF (frame_sn);
for (i = 0; i < msg_dlc && i < UDS_CF_DL_COM; i++)
send_buf[1+i] = msg_buf[i];
for (; i < UDS_CF_DL_COM; i++)
send_buf[1+i] = 0;
ZTai_UDS_Send (send_buf, UDS_VALID_FRAME_LEN);
if (msg_dlc > UDS_CF_DL_COM)
return UDS_CF_DL_COM;
else
return msg_dlc;
}
/**
* send_multipleframe - send a multiple frame msg
*
* @msg_buf : uds msg data buffer
* @msg_dlc : uds msg length
*
* returns:
* void
*/
static void
send_multipleframe (uint8_t msg_buf[], uint16_t msg_dlc)
{
uint16_t i;
uint8_t send_len;
if (msg_dlc < UDS_FF_DL_MIN || msg_dlc > UDS_FF_DL_MAX) return;
for (i = 0; i < msg_dlc; i++)
remain_buf[i] = msg_buf[i];
g_xcf_sn = 0;
send_len = send_firstframe (msg_buf, msg_dlc);
remain_pos = send_len;
remain_len = msg_dlc - send_len;
}
/*******************************************************************************
Function Definition - external API
*******************************************************************************/
/**
* network_main - network main task, should be schedule every one ms
*
* @void
*
* returns:
* void
*/
extern void
network_main (void)
{
uint8_t send_len;
// uint8_t err;
if (nt_timer_run (TIMER_N_CR) < 0)
{
clear_network ();
N_USData.indication (recv_buf, recv_len, N_TIMEOUT_Cr);
}
if (nt_timer_run (TIMER_N_BS) < 0)
{
clear_network ();
N_USData.confirm (N_TIMEOUT_Bs);
}
if (nt_timer_run (TIMER_STmin) < 0)
{
g_xcf_sn++;
if (g_xcf_sn > 0x0f)
g_xcf_sn = 0;
// OSMutexPend(UdsMutex,0,&err);
send_len = send_consecutiveframe (&remain_buf[remain_pos], remain_len, g_xcf_sn);
remain_pos += send_len;
remain_len -= send_len;
if (remain_len > 0)
{
if (g_rfc_bs > 0)
{
g_xcf_bc++;
if (g_xcf_bc < g_rfc_bs)
{
nt_timer_start (TIMER_STmin);
}
else
{
/**
* start N_Bs and wait for a fc.
*/
g_wait_fc = TRUE;
nt_timer_start (TIMER_N_BS);
}
}
else
{
nt_timer_start (TIMER_STmin);
}
}
else
{
clear_network ();
}
// OSMutexPost(UdsMutex);
}
}
/**
* network_recv_frame - recieved uds network can frame
*
* @func_addr : 0 - physical addr, 1 - functional addr
* @frame_buf : uds can frame data buffer
* @frame_dlc : uds can frame length
*
* returns:
* void
*/
extern void
network_recv_frame (uint8_t func_addr, uint8_t frame_buf[], uint8_t frame_dlc)
{
// uint8_t err;
uint8_t pci_type; /* protocol control information type */
/**
* The reception of a CAN frame with a DLC value
* smaller than expected shall be ignored by the
* network layer without any further action
*/
if(frame_dlc != UDS_VALID_FRAME_LEN) return;
if (func_addr == 0)
g_tatype = N_TATYPE_PHYSICAL;
else
g_tatype = N_TATYPE_FUNCTIONAL;
// OSMutexPend(UdsMutex,0,&err);
pci_type = NT_GET_PCI_TYPE (frame_buf[0]);
switch(pci_type)
{
case PCI_SF:
if (nwl_st == NWL_RECV || nwl_st == NWL_IDLE)
{
clear_network ();
if (nwl_st == NWL_RECV)
N_USData.indication (recv_buf, recv_len, N_UNEXP_PDU);
recv_singleframe (frame_buf, frame_dlc);
}
break;
case PCI_FF:
if (nwl_st == NWL_RECV || nwl_st == NWL_IDLE)
{
clear_network ();
if (nwl_st == NWL_RECV)
N_USData.indication (recv_buf, recv_len, N_UNEXP_PDU);
if (recv_firstframe (frame_buf, frame_dlc) > 0)
nwl_st = NWL_RECV;
else
nwl_st = NWL_IDLE;
}
break;
case PCI_CF:
if (nwl_st == NWL_RECV && g_wait_cf == TRUE)
{
if (recv_consecutiveframe (frame_buf, frame_dlc) <= 0)
{
clear_network ();
nwl_st = NWL_IDLE;
}
}
break;
case PCI_FC:
if (nwl_st == NWL_XMIT && g_wait_fc == TRUE)
if (recv_flowcontrolframe (frame_buf, frame_dlc) < 0)
{
clear_network ();
nwl_st = NWL_IDLE;
}
break;
default:
break;
}
// OSMutexPost(UdsMutex);
}
/**
* network_send_udsmsg - send a uds msg by can
*
* @msg_buf : uds msg data buffer
* @msg_dlc : uds msg length
*
* returns:
* void
*/
extern void
network_send_udsmsg (uint8_t msg_buf[], uint16_t msg_dlc)
{
if (msg_dlc == 0 || msg_dlc > UDS_FF_DL_MAX) return;
if (msg_dlc <= UDS_SF_DL_MAX)
{
send_singleframe (msg_buf, msg_dlc);
}
else
{
nwl_st = NWL_XMIT;
send_multipleframe (msg_buf, msg_dlc);
}
}
/**
* network_reg_usdata - reg usdata Function
*
* @usdata : uds msg data Function struct
*
* returns:
* 0 - ok, other - err
*/
extern int
network_reg_usdata (nt_usdata_t usdata)
{
// uint8_t err;
if (usdata.ffindication == NULL || usdata.indication == NULL || usdata.confirm == NULL) return -1;
N_USData = usdata;
// UdsMutex = OSMutexCreate(5, &err);
return 0;
}
/****************EOF****************/
作者:期权记