文章目录
- 一、简介
- (1) 应用场景
- (2) 请求格式
- (3) 重启类型
- 二、示例代码
- (1) 11_ecu_reset.c
一、简介
ECU复位服务就是可以此诊断指令来命令ECU执行自复位,复位有多种形式,依据子功能参数来区分(即客户端使用ECU复位服务来请求服务端重置,重置成功后,将直接进入默认会话)。
通常来说,ECU在收到一条诊断指令后,要先进行相应的处理,执行某些诊断操作,完毕后再发送肯定响应。但是ECU复位服务是个特例,因为它的诊断操作是复位,这时候这个ECU就会重新开始运行,此时ECU也不会记得你前面发过诊断指令,所以复位后没办法ECU就没办法再去发送诊断响应,所以要先发送肯定响应,再执行复位。
注意:从发送完肯定响应到执行复位的这段时间内,ECU是否还可以响应其它诊断请求,标准中没有规定。建议此期间ECU不接受任何请求消息,也不发送任何响应消息。
(1) 应用场景
一般而言,对于11诊断服务,主要应用场景为以下场合:
- ECU被刷写新的软件后,此时需通过11诊断服务重启该ECU使其回复到初始状态,保证一个十分干净的运行环境;
- 在产线下线标定的过程中,对于KL30供电的ECU存在一些仅在下电存储的数据,此时需要通过11诊断服务使ECU走下电流程进而完成相应数据的保存;
- 为满足特定功能的需要,输入相关标定参数给到ECU后,只有通过发送诊断服务11才能使得标定参数生效的场景;
- 对于KL30供电的ECU节点,可以使用诊断服务11使ECU快速进入休眠的场景;
上述这些应用场景较为常见,除此以外,当然还有很多面向ECU内部测试的应用场合,这里就不一一列举。
注意事项:
根据ISO14229-1标准所述,当Client向Server发送11诊断服务请求时,Server可在重置行为完成之后或者开始重启行为之前给到Client
诊断响应,但14229-1强烈推荐的一种做法是:”当Server接受到来自Client的11诊断服务请求时,Server应当先给出诊断响应然后开始重启行为“。
至于为什么如此,我想到一个场景:如果功能寻址请求11诊断服务时(未抑制正响应),在复位未完成之前,一般都会先回复NRC78让Client进行等待,那么对于Client需要根据不同的ECU节点的回复做超时监控,这无疑增加了Client负担,对于Client而言,最为简单的方法就发送完请求,各ECU节点回复正响应,然后各自完成复位操作即可。
(2) 请求格式
(3) 重启类型
由上图2所提到复位类型,复位类型作为subfunction参数来传递给到Server发生相应的重启行为,具体由以下几种类型:
- HardReset:硬复位;
- keyOffOnReset:点火开关复位;
- SoftReset: 软复位;
- enableRapidPowerShutDown:使能快速休眠流程;
- disableRapidPowerShutDown:抑制快速休眠流程;
- vehicleManufacturerSpecific:供整车制造商使用的自定义复位类型;
- systemSupplierSpecific:供系统供应商使用的自定义复位类型;
二、示例代码
(1) 11_ecu_reset.c
/********************************************************************************
* @file 11_ecu_reset.c
* @author jianqiang.xue
* @version V1.0.0
* @date 2023-05-30
* @brief ECU 复位功能
********************************************************************************/
/* 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 0x11
/* Private typedef -----------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static uint8_t ecu_reset_req = 0;
/***************软定时器创建***************/
/* Private func --------------------------------------------------------------*/
void post_func(uint8_t val) {
(void)val;
if (ecu_reset_req) {
diag_main_send_signal(SIGNAL_DIAG_RESET);
}
}
void uds11_main(nwl_msg_t* p) {
uint8_t data[10];
ecu_reset_req = 0;
if (p->len != 2) {
send_nrc_data(UDS_ID, NRC_INCORRECT_MESSAGE_LENTH);
goto end;
}
switch (p->data[1] & 0x7F) { // 子功能,bit7为应答位。 =1则不允许应答
case 0x01: // 硬件复位
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[1] & 0x80) {
// 应用无需应答
} 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
os_delay(1);
}
ecu_reset_req = 1;
break;
default:
send_nrc_data(UDS_ID, NRC_SUBFUNCTION_NOT_SUPPORTED);
break;
}
end:
return;
}
#if AUTOSAR_DIAG_SWITCH && USE_UDS_11
DIAG_SERVICE_REG(UDS_ID, DIAG_NO_SECURITY_LEVEL, (DEFAULT_SESSION|PROGRAMMING_SESSION|EXTENDED_SESSION),
(DIAG_PHYS_REQ|DIAG_FUNC_REQ), NULL, post_func, uds11_main);
#endif