19
2024
10

can控制器 uds诊断完整代码(c写的keil项目)遵循iso sae J1939标准(stm32 N32 系列MCU可用)

可以帮忙调试,QQ:778292363

二维码.png

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的软件等。‌

11.png

22.png

整个项目完整代码已经在前装车载设备上使用:

/***************************************************************************//**
    \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****************/


gzh

微信扫码关注

更新实时通知

« 上一篇

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。