一、背景

信号处理的“银弹”总是口口相传,不方便新同学快速学习。

二、目的

通过本文总结大部分信号处理相关最佳实践**,**帮助大家规避Bug,提高代码质量

三、名词解释

  1. 什么是FD、FR、SC**FD:Function Design功能设计,类似PRD,主要描述功能场景。**例如:当用户点击舒控”AUTO”,需要执行风量自动、吹风模式自动等。FR:**Function Realization功能逻辑实现,主要是将FD描述的功能进行拆解,把每个SC需要做的逻辑拆解分配。例如:热管理SC: 接收AUTO信号,计算并发送对应风量、发送风量自动信号,计算并发送对应吹风模式,发送吹风模式自动信号,发送AUTO状态ON。 座舱SC:显示对应风量和风量AUTO图标等SC:System Component design系统需求设计,主要是落实FR。**整车需求开发链路是:FD➝FR➝SC➝ECU

注意 如果遇到SC和PRD不一致的情况,需要及时拉齐,优先以SC为准。

  1. 整车网络拓扑

    缩写中文名称英文名称配置
    DCD座舱控制单元Digital Cockpit Domain全系
    VCCD中央控制单元Vehicle Central Control Domain
    ADD智驾控制单元Autonomous Driving Domain
    T-BOX车载通信模块Telematics Box

    图片展示了MS11整车网络拓扑V3.0 - 20230426中车身电子部分的信号处理信息。信号包括RLS、Rain Light Solar Sensor、光雨量传感器等,分别对应车身电子、雨量传感器、光雨量传感器。其中RLS信号由李鹤鸣2127配置,Rain Light Solar Sensor信号由左江林配置。该图片与上下文介绍的整车需求开发链路及整车网络拓扑等内容相关,直观呈现了车身电子部分的信号配置情况。

图片展示了MS11整车网络拓扑V3.0 - 20230426。图中以不同颜色线条表示信号传输方向,蓝色为下行信号,粉色为上行信号。T-BOX、ADD、DCD等单元通过Switch与VCCD相连,VCCD再与多个ECU单元连接。各单元间有信号传输,如ADD单元与多个ECU单元有信号交互。该图与上下文介绍的整车需求开发链路及网络拓扑相关,直观呈现了各单元间信号传输情况。

MS11

MS11整车网络拓扑V3.0-20230426.pdf

  1. 什么是上行信号&下行信号?从DCD发出的信号,称作下行信号;DCD接收的信号,称作上行信号。上行信号更新UI,下行信号控车。
  2. 什么是DBC文件?

DBC是DataBase Can的缩写,是CAN的数据库文件,该文件定义了整车CAN忘了各个节点控制器的通讯规则,可以理解为Android的AIDL文件。在测试过程中,可以配合PCAN和CANoe来使用,用于模拟和对手域通讯。

DBC文件格式说明

  • 报文格式:
BO_ message_id message_name ':' message_size transmitter {signal} ;
BO_ 839 VCCD_DCDCANFD_0x347: 32 VCCD
BO_ 929 DCD_DCDCANFD_0x3A1: 32 DCD

**BO_ :**固定字符串,表示报文,可以理解为一组CAN信号的集合

**message_id:**报文ID 无符号正整数

**message_name:**报文名字

**message_size:**数据帧大小 CANFD最多支持64字节,CAN最多支持8字节

**transmitter:**报文发送者

  • 信号格式:
signal = 'SG_' signal_name multiplexer_indicator ':' start_bit '|' 
        signal_size '@' byte_order value_type '(' factor ',' offset ')'
        '[' minimum '|' maximum ']' unit receiver {',' receiver} ;
         signal_name = DBC_identifier ; 
充/放电功率
SG_ VCUHVExtPortEgyTrfActPwr : 135|14@0+ (0.1,-819.1) [-819.1|819.2] "kw"  DCD
过热保护触发温度设置
SG_ DCDOvrHeatProtectTempSet : 76|5@0+ (1,29) [29|60] ""  VCCD

**SG_:**固定字符串,表示单一CAN信号

signal_name:信号名称

**multiplexer_indicator:**普通信号 or 多路复用信号。详见:下方文档

**start_bit:**在当前报文的起始位置,bit

**signal_size:**信号所占bit

**byte_order:**大小端,0=Big endian,1=Little endian,小米汽车全部使用Big endian

**value_type:**无符号 or 有符号( + 无符号,- 有符号 )

factor & offset:系数 & 偏移量,精度double,factor用于定义精度,offset用于定义最小值

📌 上行:physical_value = raw_value * factor + offset 下行:raw_value = (physical_value – offset) / factor 例如: 上行信号VCUHVExtPortEgyTrfActPwr(充放电功率),最小值是-819.1,精度0.1kW 转换关系由MCU处理。

minimum & maximum:有效的physical_value最大值&最小值, 精度double

**unit:**单位,字符串

**receiver:**信号接收者

  1. CAN信号层级:座舱MCU:负责和外域进行CAN信号通讯,处理例如:信号丢失10个周期、快三帧,Press信号的长按、raw_value和physical_value转换等。通过S32K3XX芯片对应的CANFD引脚进行CAN信号的收发。并通过SPI总线和8295芯片进行通讯。SoC QNX CarService:处理SPI总线的信号数据,进行业务处理,例如:CAN信号到CarPropertyValue的N→1 or 1→N处理,信号Value的Not_Available到CarPropertyValue.Status的映射等。然后通过prop_interface接入仪表,通过QacService提供给其他QNX侧应用。然后通过Android&QNX共享内存的方式,通过Google Protocol Buffer提供给Android CarService。Android CarService:透传QNX CarService的CAN信号给Android应用 ;对于支持频率发送的信号,可以在registerCallback中设置上报频率, 按频率发送 (速度,角度等),详见:信号接入指南

    图片展示了Android CarService与QNX CarService在汽车系统中的架构关系。左侧为QNX架构,包含App、Middleware、QNX CarService、Vehicle_core等模块,通过PPS与SPI Remote、SPI Service、SPI Driver交互,最终连接MCU。右侧为Android架构,有App、CarService、Vehicle HAL等模块,通过HIDL与Android系统交互。中间有HAB箭头连接,表明两者在系统层面有交互。该图与文档中介绍Android CarService透传QNX CarService信号给Android应用的内容相关,直观呈现了架构关系。

车辆数据服务技术分享

信号中间件详解

  1. 对手域与ECUECU CAL _V4.0 _20230327

    • 对手域:VCCD、ADD等和DCD连接的控制器。

    • ZCU:区域控制器,是车辆中的节点,用于分割电气和电子架构,并充当整车物理区域内设备(各种传感器、外围设备和执行器)的所有配电和数据连接要求的控制器。例如:左区域控制器(LZCU)、右区域控制器(RZCU)

    • ECU:电子控制器(又称作电子控制单元或电控单元,英语:Electronic Control Unit)是汽车电子系统中用来控制电气系统、电子系统及汽车子系统的嵌入式系统。DCD、VCCD、LZCU也属于ECU。

❤️ 温馨提示 目前整车的架构是所有逻辑集中在VCCD中管理,区域控制器ZCU只负责配电和执行。

  1. CANFD与CAN的区别CAN FD 是CAN with Flexible Data rate的缩写。主要区别对比:

    CANCANFD
    传输速率不同最大传输速率1Mbps速率可变,仲裁比特率最高1Mbps(与CAN相同),数据比特率最高8Mbps
    数据帧长度不同最长8字节最长64字节
    帧格式不同CANFD在CAN基础上新增了FDF、BRS、ESI位
    ID长度不同11bit12bit

❤️ 温馨提示 MS11使用的是CANFD

四、CarProperty介绍

CarPropertyManager

TODO

CarPropertyValue

public final class CarPropertyValue<T> implements Parcelable {
    private final int mPropertyId;
    private final int mAreaId;
    private final int mStatus;
    private final long mTimestamp;
    private final T mValue;
}
  • PropertyId:信号ID,多个CAN信号可以对应一个PropertyId
MASK0xF00000000x0F0000000x00FF00000x0000F0000x00000FFF
[VehiclePropertyGroup](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/android.hardware.automotive.vehicle-V2.0-java-shallow/android_common/xref/srcjars.xref/android/hardware/automotive/vehicle/V2_0/VehiclePropertyGroup.java)[VehicleArea](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/android.hardware.automotive.vehicle-V2.0-java-shallow/android_common/xref/srcjars.xref/android/hardware/automotive/vehicle/V2_0/VehicleArea.java)[VehiclePropertyType](https://cs.android.com/android/platform/superproject/+/master:packages/services/Car/car-lib/src/android/car/VehiclePropertyType.java)MiVehicleZoneN/A
MiCarSYSTEM 1
VENDOR 2
MICAR 6
GLOBAL 1
WINDOW 3
MIRROR 4
SEAT 5
DOOR 6
WHEEL 7
BODY 8
STRING 0x00100000
BOOLEAN 0x00200000
INT32 0x00400000
INT32_VEC 0x00410000
INT64 0x00500000
INT64_VEC 0x00510000
FLOAT 0x00600000
FLOAT_VEC 0x00610000
BYTES 0x00700000
MIXED 0x00E00000
BODY 0x00001000
LIGHT 0x00002000
DOOR 0x00003000
HVAC 0x00004000
WINDOW 0x00005000
SEAT 0x00006000
DRIVING 0x00007000
ENERGY 0x00008000
WARNING 0x00009000
GUARD 0x0000A000
PERIPHERAL 0x0000B000

PropertyId和CAN信号对应关系:DCD车辆数据服务-信号列表

  • AreaId:区域Id,用于区分同一PropertyId信号的不同区域
AreaArea value Enum
WINDOWVehicleAreaWindow
MIRRORVehicleAreaMirror
SEATVehicleAreaSeat
DOORVehicleAreaDoor
WHEELVehicleAreaWheel
BODYMiVehicleAreaBody

例如:出风口开关

图片展示了车辆内部出风口区域,画面中清晰标示出四个出风口位置。从左至右依次为“主驾出风口1”“主驾出风口2”“副驾出风口1”“副驾出风口2”,每个出风口旁均有对应编号。该图片与文档中介绍CarPropertyValue相关,用于说明出风口开关等信号对应的区域,直观呈现了不同出风口的位置分布。

PropertyId信号名称AreaIdCAN信号
0x65404113主驾出风口1SEAT_ROW_1_LEFT上行:HvacFirstLeVga1OnOffSt
下行:DCDFirstLeVGA1OnOffSet
主驾出风口2SEAT_ROW_1_LEFT | SEAT_ROW_1_CENTER上行:HvacFirstLeVga2OnOffSt
下行:DCDFirstLeVGA2OnOffSet
副驾出风口1SEAT_ROW_1_RIGHT | SEAT_ROW_1_CENTER上行:HvacFirstRiVga1OnOffSt
下行:DCDFirstRiVGA1OnOffSet
副驾出风口2SEAT_ROW_1_RIGHT上行:HvacFirstRiVga2OnOffSt
下行:DCDFirstRiVGA2OnOffSet
  • Status:

详见

public static final int STATUS_AVAILABLE = 0;
public static final int STATUS_UNAVAILABLE = 1;
public static final int STATUS_ERROR = 2; // 目前没有用到
public static final int STATUS_TIMEOUT = 4;
public static final int STATUS_TIMEOUT_UNAVAILABLE = STATUS_UNAVAILABLE | STATUS_TIMEOUT;
  • Value:信号的值,泛型类型。

  • Timestamp:Android的CarService收到上行信号的时间。通过SystemClock#elapsedRealtimeNanos获取。

信号接入指南

CarPropertyConfig

TODO

五、最佳实践

  1. 信号类UI如何显示?

答:上行信号的Value和Status共同进行UI显示。

  1. 什么是UI先行 & 超时回弹?

💡 最佳实践 UI先行: 由于CAN信号从DCD发送到对手域,经过对手域处理后,再通过CAN信号返回给DCD,这个过程往往比较耗时(大约150ms),为了更好的用户体验,需要UI根据下一状态先行切换。 超时回弹: UI先行后,2秒内未确认UI,回滚到原状态

图片展示了信号处理最佳实践中的UI先行及超时回弹流程。左侧蓝色圆圈内有叶片图标,代表初始状态。右侧有三个相同图标,分别由三条橙色箭头指向,表示2秒内未确认UI时,回滚到原状态。该图与文档中“UI先行后,2秒内未确认UI,回滚到原状态”的内容对应,直观呈现了这一操作逻辑。

❤️ 温馨提示 出现UI先行 & 超时回弹的前提是需要有下行信号,仪表类信号没有UI先行或超时回弹。

  1. 哪些下行信号不需要超时回弹?

💡 最佳实践 Press(btn软按键)信号不需要超时回弹,例如:座椅的高低、前后、靠背角度调节,由于上行信号(DrvrSeatHozlMotPosn)和下行信号(DCDDrvrHozlAdjHmiReq)是分开的, 对于超时逻辑,下行信号与上行信号分开,在下发Press信号时,启动计时器;

  1. 当2s内收到对应上行信号,应该把下行信号计时器移除;
  2. 当2s内没有收到对应上行信号,应该做个映射,以对应上行信号进行超时回弹处理;
  1. 信号不可用是什么?
  • 信号丢失

信号丢失 > 10个周期

  • 不可用例如:例如:PwrModVld和SteerWhlHeatFcnAvlSts

    • Value值为“Not_Available”,车控类预留,几乎不会上报,但是我们也要处理。

    图片展示了空调系统开关返回状态的相关信息。左侧为“空调系统开关返回状态”,右侧依次列出HvacOnOffSt、HVAC on / off state、0x0:Off、0x1:On、0x2:Not_Available、0x3:Not_Used。其中,0x2:Not_Available以红色框突出显示。该图片与上下文紧密相关,上下文在介绍空调系统开关信号时提到,上行的Value定义和下行信号Value定义可以不一致,此图直观呈现了空调系统开关返回状态的Value定义情况,帮助理解信号定义的多样性。

🏅 小知识 从“空调系统开关”信号,我们可以看出,上行的Value定义和下行信号Value定义可以不一致。

  • xxxVld 和 xxxAvlSts

🏅 小知识 Vld用于表示XX信号数据有效性,比如电源模式有效性(PwrModVld),挡位有效性(VCUGearLvrForDispVld);AvlSts用于表示车控XX信号的可用性,一般会伴随“不可用原因”信号,例如:方向盘加热可用性(SteerWhlHeatFcnAvlSts)和方向盘加热不可用原因(SteerWhlHeatFcnNotAvlRsn)。

当前Value信号是否丢失Status
Not_Available¹丢失STATUS_TIMEOUT_UNAVAILABLE
正常值丢失STATUS_TIMEOUT
Not_Available¹未丢失STATUS_UNAVAILABLE
正常值未丢失STATUS_AVAILABLE

Value值为“Not_Available” 或 xxxVld为无效 或 xxxAvlSts为不可用

详见:信号 Status 值扩展说明

💡 UI处理最佳实践 因此在信号处理中不仅仅要处理对应的值,也要处理信号的Status。具体处理细节请遵循SC&PRD

[飞书 Mindnote 嵌入块] (token=B1jXbqshgmBhqSneWYccDKG2n0g) — 飞书原生 mindnote 结构,无法转 markdown,请前往 原文 查看

  1. Not_used & Reserved 类信号如何处理?由于信号的signal_sizes是信号所占的bit,对应的Value的取值范围为,因此会有一些bit没有用到或作为保留。

💡 最佳实践 绝大部分的Not_used & Reserved都被QNX CarService过滤掉了。

  1. 组合信号如何处理?

💡 最佳实践 由于组合信号可能涉及多个报文分组的上行信号,会有先后顺序或信号丢失的情况,因此需要对全部信号进行缓存,当某个信号更新时,更新对应信号,并将所有信号的结果进行组合更新UI。 对于非常复杂的组合信号,可以让系统工程老师提供《信号和UI对照表》,例如:充放电状态UI显示—供理解

参考代码:

int signalAVal = 0, signalBVal = 0;
boolean signalAEnable = false,signalBEnable = false;
public void onChangeEvent(CarPropertyValue value) {
    int propertyId = value.getPropertyId();
    switch(propertyId) {
        case SIGNAL_A:
            signalAVal = (int) value.getValue();
            signalAEnable = VehiclePropertyUtil.isAvailable(value);
            refreshUi();
            break;
        case SIGNAL_B:
            signalBVal = (int) value.getValue();
            signalBEnable = VehiclePropertyUtil.isAvailable(value);
            refreshUi();
            break;
    }
    private void refreshUi() {
        int ret = signalAVal + signalBVal;
        bool enabled = signalAEnable && signalBEnable;
    }
}

💡 最佳实践 如果组合信号更新同一个ICON的不同状态,则需要分开更新,例如:座椅加热通风,一个ICON有AUTO和State两个信号控制状态,则需要分别更新,而不是使用缓存值。 原因:当下行State-3,UI会现行到3,这时如果Auto信号变化时,如果getStateValue()则使用的是旧缓存值,如此就打破了UI现行的逻辑,此时就出现UI先行到了3,但是又刷新到了0,等真正3上来了又变成了3的闪跳现行。

图片展示了Seekbar的跟手下发和抬手下发效果。左侧灰色图标代表跟手下发,中间蓝色图标代表抬手下发。跟手下发时,图标从灰色变为蓝色,再变为灰色;抬手下发时,图标从灰色变为蓝色,再变为灰色,最后变为蓝色。该图与上下文介绍的跟手下发和抬手下发概念相关,直观呈现了两种下发方式下图标的变化情况。

public void onChangeEvent(CarPropertyValue value) {
    int propertyId = value.getPropertyId();
    switch(propertyId) {
        case SIGNAL_A_STATE:
            refreshUi(value, null);
            break;
        case SIGNAL_A_AUTO:
            refreshUi(null, value);
            break;
    }
    private void refreshUi(CarPropertyValue state, CarPropertyValue auto) {
        if (state != null) {
            // 刷新State
        }
        if (auto != null) {
            // 刷新Auto
        }
    }
}
  1. 什么是Seekbar的跟手下发&抬手下发?示例:空调风量设置、氛围灯颜色选择、电动出风口XY坐标设置、能量管理充放电限值设置。舒控出风位置:

    图片展示了空调舒控出风位置的示例。画面中,空调出风口处有白色烟雾状的气流,气流从出风口处吹出,呈现出柔和的弧形。出风口位于车门内侧,周围有黑色的内饰装饰。该图片与上下文内容相关,用于直观呈现舒控出风位置,帮助理解空调风量设置等跟手下发示例中的出风情况。

  • 跟手下发:滑动过程中下发信号。

优点:滑动中可多次下发信号,车辆状态可以实时更新 缺点:处理不当容易造成Thumb抖动

用于对实时性要求高的信号,这类信号会通过车辆状态给用户带来实时的反馈,用户跟着感觉调节,调节到满意的位置即可松手,例如:空调风量设置、氛围灯颜色选择、电动出风口XY坐标设置。

图片展示了一个滑动条,白色圆形滑块位于右侧,蓝色箭头指向滑块滑动方向。滑动条下方有多组上下方向的箭头,可能代表信号的下发与上行。这与文档中关于对实时性要求高的信号处理的内容相关,如空调风量设置等场景中滑动操作时的信号处理。文档提到滑动中可多次下发信号,但处理不当易造成Thumb抖动,最佳实践是开始滑动时停止上行信号对UI更新,滑动中持续下发信号,下发最后一个信号后若2秒内无信号则主动校准并恢复上行信号对UI更新。

💡 最佳实践 开始滑动时停止上行信号对UI更新(上行信号可持续监听),以免发生抖动。滑动中持续下发信号,下发最后一个信号后开始2秒计时,如果2秒内没有信号下发,第2秒主动调用getProperty信号用于校准,然后恢复上行信号对UI更新。

  • 抬手下发:抬手后下发一次信号

优点:不会造成抖动(忽略短时间内多次滑动的情况) 缺点:无法在滑动中实时改变信号

用于对实时性要求不高的信号,这类信号不会给用户带来实时的反馈,例如:能量管理充放电限值。

图片展示了一个类似SeekBar控件的示意图。画面中有一条橙色长条,上面有一个白色圆形滑块,蓝色箭头从左指向滑块,表示滑动方向,滑块下方有两个橙色箭头,可能示意不同的状态或操作方向。该图与文档中关于自定义“类SeekBar”控件滑动的内容相关,可辅助理解文档中提及的无极滑动等概念,直观呈现滑动相关元素和方向。

  1. 自定义”类SeekBar”控件的无极滑动和分段吸附滑动有什么区别?
  • 无极滑动:

优点:滑动体验丝滑 缺点:处理不当容易造成细微抖动

图片展示了无极滑动时的信号处理逻辑。当前滑动值为50.5,下行信号四舍五入发送51,上行返回信号51,UI确认51。该图与文档中“上行返回信号进行UI确认前,先判断当前的UI位置四舍五入后是否和上行信号值相等,如果相等,保留Thumb当前位置即可,反之则更新UI”的最佳实践内容相关,直观呈现了四舍五入处理后的信号值及UI确认情况。

💡 最佳实践 上行返回信号进行UI确认前,先判断当前的UI位置四舍五入后是否和上行信号值相等,如果相等,保留Thumb当前位置即可,反之则更新UI。

❤️ 温馨提示 滑动到两个整数数值之间时,下发逻辑按照 四舍五入 或 下取整 或 上取整,请根据SC or 产品文档描述决定。

  • 分段吸附滑动

优点: 信号处理简单 缺点:滑动有些许顿挫感

  1. SC/PRD描述的逻辑应该应用层实现吗?

SC/PRD中有一些逻辑,例如舒控PRD:当用户点击”A/C”、改变风量、改变出风模式时退出”AUTO”;在下电时,AUTO模式需要进行记忆。这些其实是对手域的逻辑,应用层对于信号的处理绝大部分是“显示”和“控制”,极少部分需要做逻辑兜底处理。

💡 最佳实践 一定要和系统工程、产品达成一致该功能由对手域实现,DCD不需要做兜底处理后,结论同步测试。防止需求遗漏。

  1. 有显示和设置信号功能的Dialog(二级页)如何处理?

预约出发时间CAN信号:12:00

图片展示的是一个TimePicker界面,用于设置出发时间。界面中TimePicker显示时间为12:00,有上午和下午选项,下方有“确定”按钮。右侧显示外部文本“每天 上午 12:00”。图片与上下文关系紧密,上下文讨论了预约出发时间CAN信号为12:00时,打开Dialog时Value是否跟随信号的问题,图片直观呈现了TimePicker界面及显示的外部文本,辅助说明了相关最佳实践。

打开Dialog时Value是否跟随信号?

例如:充放电-预约出发时间设置Dialog,当前信号为12:00,设置信号11:00,点击确定关闭Dialog并下发信号,在信号回弹之前立即打开Dialog,此时会有两种选择:

  1. Dialog跟随信号:此时TimePicker显示,12:00
  2. Dialog跟随外部显示:此时TimePicker显示,11:00

💡 最佳实践 建议跟随外部显示,这样符合UI先行原则,具体情况需要和产品确认。

Dialog是否监听信号?

例如:充放电-预约出发时间设置Dialog,当前CAN信号为12:00,设置信号11:00,点击确定关闭Dialog并下发信号,在信号回弹之前立即打开Dialog,并快速设置信号为10:00,此时会有两种选择:

  1. Dialog监听信号:此时看到,TimePicker被拨到10:00后,TimePicker快速超时回弹到了12:00。
  2. Dialog不监听信号:外部文本信号回弹到12:00,Dialog TimePicker时间不变(10:00)。

💡 最佳实践 不建议监听信号,只显示信号的“快照”即可,具体情况需要和产品确认。

  1. 多Tab快速点击如何避免闪跳?

核心逻辑&处理方式类似SeekBar跟手下发。

  1. 信号缓存与过滤的作用是什么?

💡 最佳实践 一些底层信号会频繁的上报,但是内容更新的频率不高,为了防止UI每次刷新相同的内容,我们可以做一层缓存层,缓存对应的信号,并根据value、status、areaId等信号是否变化进行相应的缓存&UI刷新 或 忽略。

  1. 复杂信号的合并

💡 最佳实践 由于一些业务逻辑要求,需要一些信号组合上报并显示对应的UI。这样会增加业务的复杂程度。对于多个业务通用且比较复杂的信号组合,我们可以和系统工程老师协商,合并成单一信号,从而简化业务开发逻辑。

例如:

  • 仪表的组合信号 ➝ TT协议
  • 充电口盖状态ChrgLidSts & ChrgLidSoftBtnDisp ➝ ChrgLidCurSts
  1. 单按钮快速点击

TODO

循环模式和循环模式自动的情况,需要一起不监听。

六、信号分类

  1. 什么是配置字?用于标识车辆的**一个可变项目。**存储在MCU的EEPROM中,QNX端不做存储,系统上电时每次动态从MCU端获取。

例如:

英文名称中文名称信号
High Voltage Battery Chemical Type高压(动力)电池类型
0x1: lithium iron phosphate battery 磷酸铁锂电池
0x2: Ternary lithium battery 三元锂电池
HvBattChemicalConfig

💡 最佳实践 对于配置字类信号,无需进行监听,在应用(模块)启动时主动获取一次即可。对于后续购买类配置,生效需要重启DCD(应用),因此启动时主动getProperty即可满足。

整车配置系统介绍-2022215.pptx

variant 配置字方案

  1. 什么是内部信号?用于DCD内部通讯的信号,发送方和接收方都是DCD,例如:公里和英里切换信号DstUnitDisp。反之如果发送方或接收方是外域的信号,称作外域信号。
  2. 机械类信号如何处理?

机械类信号由于机械本身的限制,存在“正在运动”的中间状态。

  • 按钮类机械信号,例如:充电口盖打开与关闭、外后视镜的折叠与展开。

💡 最佳实践 由于中间状态时间较长,UI状态不能先行到下一状态,因此需要给用户一个“信号处理中”的提示,例如:Loading动画,文案提示等。

💡 最佳实践 频繁的高速滑动SeekBar(下发信号)会加快机械结构的磨损,甚至会导致机械故障和损坏。因此,对于机械类信号,我们应该尽量控制信号的下发频率,在不影响用于体验的前提下,通过某种策略进行采样。

🏅 小知识 对于一些机械组件,自身有一套防玩机制,多次开关会触发“控制不可用”状态原因为“防玩模式禁止XXX”。例如:充电口盖开启&关闭、外后视镜展开&折叠。

  1. Telltale灯(TT灯)是什么?在MS11中,座舱MCU按照一定频率将整车的多个CAN信号进行组合计算,然后将计算结果按照TT协议编码成一个ByteArray,再通过一个PropertyId为0x61709149的CarPropertyValue上报给上层应用。从而控制TT灯的状态(点亮、熄灭、闪烁),目前TT灯已经在中控屏StatusBar、仪表(QNX)、HUD、功能安全校验、备份渲染中使用。TT协议分为动态协议(2个Bytes)和静态协议(1个Byte)两种。TT灯解析程序,用于将数组解析成可读的TT协议,极大的提高了Bug分析效率:

🏅 小知识 Telltale灯,以下简称TT灯,即警告灯,用于提醒操作者车辆中存在潜在问题或需要注意的事项。

数组Index01234。。。。7576。。。。
说明点亮的动态灯个数动态信号A动态信号BP挡R挡
IdpayloadIdpayloadpayloadpayload

为了和CarPropertyValue中的Value进行区分,TT协议中对应信号值我们称为payload。

图片展示的是Android系统中MiCarPropertyService的onPropertyChange日志信息。时间戳为2023 - 05 - 15 16:21:54.439,进程ID为2601 - 2652,日志来源为com.android.car。日志内容显示,信号值为[13, 3, 0, 11, 1, 12, 1, 14, 1, 15, 1, 17, 1, 19, 1, 20, 1, 22, 1, 24, 1, 26, 1, 36, 1, 38, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

👍 MCU的工作:

  1. 通过对各种组合信号(功能信号和电源模式信号)进行汇总,控制TT灯的状态(点亮、熄灭、闪烁、呼吸动画)
  2. TT灯位置排序
  3. 功能安全灯的校验
  4. 处理TT灯的信号超时以及自检逻辑

💡 最佳实践UI层面上TT灯的状态分为四种:显示、隐藏、闪烁、呼吸动画。 显示:View.VISIBLE 隐藏:View.GONE 闪烁:按照一定频率切换View.VISIBLE & View.INVISIBLE,注意这里不是GONE,原因见下图。 呼吸动画:Alpha动画 0⇋1 交替变化。

图片展示了信号处理中信号分类的流程。左侧为信号源,中间是信号处理环节,右侧是信号结果。信号源处有“H”标识,左侧箭头指向信号源,中间箭头指向信号处理,右侧箭头指向信号结果,信号结果也带有“H”标识。该图与文档中“信号分类”部分内容相关,直观呈现了信号从源到处理再到结果的流程。

图片展示了信号处理中信号分类的示例。左侧和右侧各有一个带有绿色箭头和“H”标识的蓝色边框框,中间有一个同样带有“H”标识的蓝色边框框。这可能代表信号在不同状态或阶段的示例,用于说明信号分类在信号处理中的应用,与上下文介绍的信号分类内容相呼应。

TT灯协议TT灯解析程序
E4[TT灯方案 V01](https://mi.feishu.cn/docx/K9kwdLo7loJ9JwxHb8hc3a01nzf) [MS11_VehicleCore_SPI_Protocol](https://mi.feishu.cn/sheets/NVsLsDglEhFvXFt0myKcNXTsnRb) [E4-python脚本可视化解析TT协议数组](https://mi.feishu.cn/docx/Xtr1ds1kVo4nNGxDwnMcGwDjn9c)[TT灯解析程序Gerrit](http://gerrit.auto.mioffice.cn/admin/repos/cockpit/Plugins)
E4U1[TT灯方案 V02 E4U1](https://mi.feishu.cn/docx/Ecund8owyohtwmxsS26coFctnud)[E4U-python脚本可视化解析TT协议数组](https://mi.feishu.cn/docx/BOVSd6dxUoWg0gxOlfccwzbZnic)
  1. TT灯与法规由于TT灯涉及车辆的安全性,因此国标对TT灯的图案、颜色等行了严格规定,详见:

  2. 什么是Press信号?

Press信号,又被称为软按键 或 Btn类信号,这种信号通常用于复杂的状态切换类信号,例如:循环模式。或用于数值 +/-类信号,例如:座椅前后调节、风量+/风量-等。Press信号一般有对应的上行信号用于表示结果。

💡 最佳实践 Press信号由于“下一状态”未知,因此无法进行UI先行,而且Press信号仅仅用于下行控车,因此也不存在超时回弹。在下发此类信号时应该使用无回弹计时器的setProperty下发。 由于无法进行UI先行,需要针对相应上行信号的响应时间进行评估。如果对应上行信号响应较慢,会产生点击后长时间无反应的体验问题。可以通过添加按钮按压动效,减少无法UI先行带来的体验问题。

  1. CAN E2E作用是什么?

🏅 小知识 E2E Protection,全称End to End Protection,即端到端保护机制的简称。在该机制中,发送端和接收端之间的信息受到保护,且对传输的信息进行一致性和完整性的校验,不受信息传递过程中协议转换或者路由情况的影响。

  • 信息的重复发送 (Repetition of Information),相同的信息被收到了多次
  • 信息的丢失 (Loss of Information),整条或者信息的一部分在通信过程中丢失
  • 信息的延迟 (Delay of Information),接收信息的时间异于期望的时间
  • 信息的插入 (Insertion of Information),多余的内容被插入到信息中
  • 假冒的或者不正确的寻址 (Masquerade or Incorrect Addressing of Information),假冒的发送者发送未认证的信息被接收端接受,或者正确的信息被错误的接收端接受
  • 信息顺序错误 (Incorrect Sequence of Information),数据流中的信息顺序错误
  • 信息破损 (Corruption of Information),信息的内容被篡改
  • 向多个接收端发送非对称信息 (Asymmetric information sent from a sender to multiple receivers),接收端收到的数据不一致
  • 仅部分接收端收到发送者的信息 (Information from a sender received by only a subset of receivers
  • 阻塞通信通道 (Blocking access to communication channel)
  1. 什么是SOA信号?基于以太网的 SOA 架构传输的信号,VCCD/DCD/Tbox/ADD 都部署 DDS 协议栈,为跨域间通信提供服务接口。 例如:智驾SR,ADD收集各种传感器的数据,通过计算后把坐标和物体类型通过DDS传给DCD,智驾Unity根据坐标渲染对应3D模型。下图红框内的,即,ADD & DCD 的 ETH

    图片展示了智驾SR系统中ADD&DCD的ETH部分。左侧为DCD-3001座舱控制单元,右侧为ADD-2001智驾控制单元。两者通过Switch连接,其中红框内标注的“ADD_ETH 1000Base-T1”和“DCD_ETH 1000Base-T1”为关键部分,分别对应ADD和DCD的以太网接口。该图与上下文紧密相关,直观呈现了基于以太网的SOA架构中ADD和DCD间通过DDS协议栈进行跨域间通信的信号传输情况。

七、工具介绍

  1. CAN工具简介:
  • CANoe(CAN open environment)

CANoe是Vector Informatik所开发的软体开发及测试工具。主要用在汽车制造商以及电子控制器(MCU)供应商,可用在电子控制器网路或个别电子控制器的开发、分析、模拟、测试、诊断及启动。可以适用于许多的车用网路协定,因此适合用在燃油车、油电混合车及电动车电子控制器的开发。其中的模拟及测试机能是由CAPL程式语言进行的。

图片展示的是CANoe-VN5620设备,为Vector品牌。设备外观为黑色,边缘有红色装饰,正面有“VN5620 Ethernet/CAN Interface”标识。设备左侧有ETH 1/2和ETH 3/4接口,右侧有CAN 5/6接口。该图片与文档中介绍CANoe-VN5620工具的内容相关,直观呈现了该设备的外观及接口配置,帮助读者更清晰地了解其外观形态。

CANoe -VN5620

👍 优点

  1. 可以进行CAN信号回灌,用于快速定位排查问题,例如:回灌能耗曲线等复杂CAN信号
  2. 可以测试下行信号
  3. 可以无缝切换各个信号值
  4. 图形界面强大,可以自定义信号发送面板
  5. 可以轻易模拟信号丢失
  6. 对E2E信号支持稳定

👎 缺点 贵!

PCAN-USB FD可以将CAN和CAN FD网络的报文通过USB连接到电脑,用于监控CAN网络。也可以发送、保存、过滤CAN报文。电气隔离达到500V。

图片展示的是PEAK系统USB转串口适配器。主体为黑色,正面印有白色“PEAK”及“System”字样,下方有多个接口。右侧连接一根黑色USB线,线头为USB接口。该适配器用于将USB接口转换为串口,可连接到车辆CAN总线,用于获取车辆拨杆CAN Log等操作,是座舱测试中获取车辆拨杆CAN数据的工具。

座舱测试老师开发:车机助手使用手册

  1. Mock信号

Mock value

  • 可以不通过CAN模拟器,直接修改CarPropertyValue。

车辆信号调试-Q&ACarService与VHAL

pps_mock工具使用方法

  • Mock Not_Available

通过改变VehiclePropertyUtils.isPropertyAvailable进行mock

  1. 获取车辆拨杆CAN Log

    • 左侧拨杆向自己拉8秒
    • 记住当前时间和车辆编号
    • 向测试or系统工程老师要CAN Log

八、PRD/SC/Figma 评审CheckList

❤️ 温馨提示 Level 1:评审时现场向系统工程、产品、设计提问。 Level 2:评审前看PRD/SC/Figma,把相关问题发给系统工程、产品、设计。评审会进行现场解答。 Level 3:培养系统工程、产品、设计,养成思考如下问题的能力。

  1. 什么类型的信号?控车、显示、仪表?
  2. 上行 or 下行的信号?
  3. 如果是控车信号,使用Set信号还是Press信号?
  4. SeekBar类组件,抬手下发还是跟手下发?
  5. 信号丢失或value==Not_Available,UI如何显示?
  6. 是否是机械信号?是否有中间态?Figma是否有Loading动效或相关提示?
  7. 信号是否过于复杂可以合并?
  8. 需要做超时回弹吗?
  9. 显示浮点数?显示几位小数?四舍五入 or 下取整 or 上取整?
  10. 时间类信号是否跟随系统时间单位制式?12小时制 or 24小时制?
  11. 有没有AreaID的概念,如果有用那个AreaID?
  12. 快速点击会不会导致闪跳?
  13. PRD/SC中是否有特殊逻辑,特殊逻辑是对手域处理吗?
  14. Dialog是否要监听信号的上报,是否支持超时回弹?
  15. 是否支持单位切换?例如:胎压的三种单位,bar、kPa、psi
  16. 这个信号有特许权限吗?申请特许权限了吗?配置特许权限白名单了吗?
  17. Enable==false时候是否保持原值?
  18. UI的设计是否有覆盖边界情况?边界情况如何显示?
  19. 上行信号收到超过边界外的Value如何兜底?
  20. UI状态和组合信号如何对应?
  21. 配置字高、低配如何显示该功能?
  22. 信息展示类信号Figma设计时是否考虑了文案过长的显示不全的问题?
  23. 是否存在同一界面两个UI控件同时显示A信号,其中一个UI修改A信号,这时候另一个UI会延时更新UI。

九、注意事项

❤️ 温馨提示 新增添加信号,需要检查对应的权限,是否已经添加到AndroidManifest.xml,对应的权限是否已经配置到特许权限白名单中,否则会导致应用or系统崩溃。

Android 添加特许权限白名单

十、未来计划

  1. 和姚鹏老师沟通做一个信号“快照”功能,打印在bugreport里边,用于快速分析线上问题。
  2. 计划后续做一个“信号集成SDK”,包含一些通用信号逻辑的处理,方便新增业务快速、低成本承接信号类需求。

十一、结束语

本文写到这里只是体现了“信号处理”技巧的冰山一脚。仅仅作为抛砖引玉,让我们共同维护这篇文档,把更多“信号处理”技巧分享给大家。

兵无常势,水无常形;能因敌变化而取胜者,谓之神。——《孙子兵法·虚实》

希望大家在处理信号类需求的时候,能够像战神一样,战无不胜,一往无前!

十二、感谢

感谢各位老师的细心解答:

@丁艳玲 @曹旭 @康森源 @汪杨杨 @王建洲 @姚鹏 @张佃伦

十三、Q&A

更新记录:

更新内容更新时间
V1.0初版2023.06.15
V.1.1添加车辆拨杆获取CAN Log2023.07.03