文章目录

  • 一、简介
  • 二、 应用场景
  • 三、通信控制基本原理
  • 四、服务请求
  • 请求格式
  • 请求实例
  • 服务响应
  • 正响应格式
  • 负响应NRC支持
  • 五、常见Bug大揭秘
  • 六、示例代码
  • 28_comm_ctl.c


[AUTOSAR][诊断管理][ECU][] 通信控制_诊断管理

一、简介

根据ISO14119-1标准中所述,诊断服务28服务主要用于网络中的报文发送与接受,比如控制应用报文的发送与接收,又或是控制网络管理报文的发送与接收,以便满足一定场景下的应用需求。

下列文中使用到的Client可直接理解为上位机Tester,Server可直接理解为接受Tester诊断请求的ECU。

二、 应用场景

一般而言,对于28诊断服务,主要应用场景为以下场合:

  • 存在某些特殊的测试场景,比如只希望接收或者发送对应的网络管理与应用报文;
  • 绝大多数情况下应用在刷写ECU的过程中,即在预编程条件下执行28服务功能寻址便可以抑制总线应用报文与网络管理报文的发送与接收,以便减少网络总线负载,提高ECU下载效率,同时刷写结束后也要执行28服务使能对应控制报文的发送与接收,在此过程中一般会配合85服务一起使用。

三、通信控制基本原理

如下图1所示,针对28服务的通信控制过程会经过如下几个AUTOSAR BSW模块进行处理,然后完成最终的通信控制,具体步骤如下:

  1. Tester发送28通信控制服务请求给到Server,Server会将该诊断报文请求传递至DCM模块;
  2. DCM模块调用28服务对应的上层应用函数首先进行输入参数的基本校验,校验无误之后然后传递相关控制模式请求至BswM模块;
  3. BswM模块根据静态配置的规则来实现对应请求中的通道通信状态控制;(常见的模式控制为3X4 = 12种)

如下表1所示,列举出了常见的12种的通信控制模式:

[AUTOSAR][诊断管理][ECU][] 通信控制_AUTOSAR_02


如下图1所示为28通信控制的原理图,可以看到28诊断服务经过DCM,BswM,Com,NM完成整个上述12种通信模式的控制。其中蓝色表示的部分为最终完成通信控制的函数体。

[AUTOSAR][诊断管理][ECU][] 通信控制_28_03

四、服务请求

服务请求是Client发送给到Server的诊断服务指令。

请求格式

按照ISO14229-1标准所述,如下图2所示为28服务诊断请求格式,即上述通信控制原理中诊断服务请求格式:

[AUTOSAR][诊断管理][ECU][] 通信控制_ECU_04


值得注意的是28服务诊断请求中的nodeIdentificationNumber仅在subFunction等于4或者5才有效,否则#4,#5参数可以不存在。下图3中各参数解释如下:

[AUTOSAR][诊断管理][ECU][] 通信控制_诊断管理_05


如下图4所示,为上述subfunction(control Type)中的各项取值的具体含义:

[AUTOSAR][诊断管理][ECU][] 通信控制_诊断管理_06


如下图5所示为communicationType的各项取值具体含义:

[AUTOSAR][诊断管理][ECU][] 通信控制_AUTOSAR_07

请求实例

以抑制网络管理报文发送为例,28服务诊断请求实例如下图6所示:

[AUTOSAR][诊断管理][ECU][] 通信控制_通信控制_08


以控制远程特定地址节点进入仅诊断模式为例,节点地址为0x00 0A, 28服务诊断请求示例如下:

[AUTOSAR][诊断管理][ECU][] 通信控制_ECU_09


关于控制控制远程特定地址节点进入正常工作模式,这里就不一一列举,具体message Flow可参考ISO14229-1规范。

服务响应

服务响应是针对Client对Server诊断请求的响应。

正响应格式

如下图8所示,为28诊断服务的正响应格式:

[AUTOSAR][诊断管理][ECU][] 通信控制_通信控制_10


从上图中可以看出,28诊断服务的正响应由以下三个部分组成:

  • Response ID:该参数固定为SID+0x40 = 0x68;
  • SubFunction:该参数为上述诊断请求格式中controlType;

正响应实例
抑制网络管理报文发送

如下图9所示,为上述28 01 02请求示例所对应的正响应:

[AUTOSAR][诊断管理][ECU][] 通信控制_诊断管理_11

其中,0x01就是跟诊断请求中的controlType保持一致即可。

控制远程特定地址节点进入仅诊断模式

如下图10所示,则为上述28 04 01 00 0A的所对应的正响应。

[AUTOSAR][诊断管理][ECU][] 通信控制_诊断管理_12

负响应NRC支持

绝大多数情况下,Server针对Client的请求都会给到正响应,比如发生重启前需确保整车处于安全状态,如引擎熄火,车速不能超过3km/h等,或者为了防止不按照诊断请求格式进行请求,那么Server需要通过某种方式来告诉Client执行不成功的原因在哪里以便于调查问题直至得到正响应。

因此ISO14229-1针对所有的诊断服务提供了一种统一的诊断负响应的诊断格式:7F +SID + NRC。

其中NRC全称为Negetive Responce Code,每个NRC具有唯一的含义来代表当前诊断请求错误的原因所在。当然每个诊断服务支持的NRC不尽相同,具体支持的NRC需要参考ISO14229-1标准文档,对于27服务而言支持的NRC如下表2:

[AUTOSAR][诊断管理][ECU][] 通信控制_28_13

  • 当诊断请求的subfuntion不在Server支持的范围内时,则Server会回复”7F 28 12“;
  • 当发送报文长度或者格式不对时,则Server会回复"7F 28 13";

例如当尝试请求复位时且当前车速条件不满足,此时Client发送诊断指请求时,Server将会回复“7F 28 22”来告诉请求者当前进入编程会话的条件不满足,请再次检查进入编程会话的条件。

  • 当communicationType与nodeIdentificationNumber均超出规定的范围时,则Server会回复“7F 28 31”;

五、常见Bug大揭秘

对于从事过UDS开发的小伙伴可能会发现,其实针对每个服务的Bug都是有迹可循的,万变不离其宗,绝大多数问题都是由于针对需求理解不清晰或者其他人为因素导致的问题。

因此,为了方便大家能够在工作过程中能够快速找到问题症结所在,特将了解到的常见28服务Bug分享给到大家,当然具体问题还是要具体

[AUTOSAR][诊断管理][ECU][] 通信控制_ECU_14


分析,这里所列出的只是比较典型且出现错误次数较多的Bug,仅供参考。

六、示例代码

28_comm_ctl.c

/********************************************************************************
* @file    28_comm_ctl.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2023-05-30
* @brief   通信控制
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "modules.h"
#include "os_api.h"
#include "edebug.h"
#include "kv_sys.h"
#include "ecu_ble_uart.h"
/* Private includes ----------------------------------------------------------*/
#include "std_math.h"
#include "app_can.h"
#include "can_nm.h"
#include "app_nm.h"
#include "diag_main.h"
/* Private define ------------------------------------------------------------*/
#define UDS_ID    0x28

/* Private typedef -----------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/***************软定时器创建***************/
/* Private func --------------------------------------------------------------*/
void uds28_main(nwl_msg_t* p) {
    uint8_t req_type = 0; // 0-使能接收和发送 1-使能接收和禁止发送 2-禁止接收和使能发送 3-禁止接收和禁止发送
    uint8_t data[10];
    if (p->len != 3) {
        LOGE("len err != 3");
        send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
        goto end;
    }
    req_type = p->data[1] & 0x7F;
    if (req_type > 3) {
        LOGE("Unsupported,sub:%02x", p->data[1]);
        send_nrc_data(UDS_ID, NRC_SUBFUNCTION_NOT_SUPPORTED);
        goto end;
    }
    if ((g_car_ste.IPB.bit.VehicleSpeedVld == 1) && (get_car_speed() > 3)) {
        send_nrc_data(UDS_ID, NRC_CONDITION_NOT_CORRECT);
        goto end;
    }
    if (p->data[2] > 3) {
        LOGE("Unsupported,sub2:%02x", p->data[2]);
        send_nrc_data(UDS_ID, NRC_REQUEST_OUT_OF_RANGE);
        goto end;
    }
    LOGI("%x,%x", get_nm_msg_tx_ste(), get_nm_msg_rx_ste());
    switch (p->data[2]) {
        // 应用报文
        case 0x01:
            switch (req_type) {
                case 0x00:
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    break;
                case 0x01:
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    break;
                case 0x02:
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    break;
                case 0x03:
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    break;
            }
            break;
        // 网管报文
        case 0x02:
            switch (req_type) {
                case 0x00:
                    can_nm_msg_tx_en();
                    can_nm_msg_rx_en();
                    break;
                case 0x01:
                    can_nm_msg_tx_disa();
                    can_nm_msg_rx_en();
                    break;
                case 0x02:
                    can_nm_msg_tx_en();
                    can_nm_msg_rx_disa();
                    break;
                case 0x03:
                    can_nm_msg_tx_disa();
                    can_nm_msg_rx_disa();
                    break;
            }
            break;
        // 网管报文和应用报文
        case 0x03:
            switch (req_type) {
                case 0x00:
                    can_nm_msg_tx_en();
                    can_nm_msg_rx_en();
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    break;
                case 0x01:
                    can_nm_msg_tx_disa();
                    can_nm_msg_rx_en();
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    LOGI("%x,%x", get_nm_msg_tx_ste(), get_nm_msg_rx_ste());
                    break;
                case 0x02:
                    can_nm_msg_tx_en();
                    can_nm_msg_rx_disa();
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 0);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    break;
                case 0x03:
                    can_nm_msg_tx_disa();
                    can_nm_msg_rx_disa();
                    app_can_tx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    app_can_rx_msg_ctrl(CTL_BY_DIAG_SRV, 1);
                    break;
            }
            break;
        default:
            break;
    }
    if (p->data[1] & 0x80) { // 子功能,bit7为应答位。  =1则不允许应答
        // 应用无需应答
    } else {
        // 回复正响应码  单帧格式: len, 服务ID|0x40, 子功能ID,
        data[0] = 2;  // 数据总长度=数据长度+服务号
        data[1] = UDS_ID | 0x40;   // 服务号,回复上位机需要 |0x40
        data[2] = p->data[1];
        memset(&data[3], 0xAA, 5);
        app_can_enqueue_msg(CAN_MSG_EVENT_SEND, NWL_RES_ADDR, data, 8);
    }
    g_p2_service_time_remaining = 0; // 如果发送诊断报文,则清除倒计时。P2_SERVER_MAX
end:
    return;
}

#if AUTOSAR_DIAG_SWITCH && USE_UDS_28
DIAG_SERVICE_REG(UDS_ID, DIAG_NO_SECURITY_LEVEL, (EXTENDED_SESSION), (DIAG_PHYS_REQ|DIAG_FUNC_REQ),
                 NULL, NULL, uds28_main);
#endif