Skip to content

DataCenter 是集度 OTX 代理插件中的全局单例数据中心,作为跨模块共享状态的唯一汇聚点,统一管理从云端服务器获取的车辆订单信息、ECU 安全常量、证书密钥、EOL 密钥、诊断数据、DTC 白名单等核心运行时数据。它采用静态成员变量 + 懒汉单例的设计模式,确保所有模块通过一致的访问路径读写同一份数据副本,避免了数据冗余和状态不一致问题。

Sources: jidu_dataCenter.h

架构设计:单例模式与全局静态存储

DataCenter 类采用经典的懒汉式单例(Lazy Singleton)模式,通过 getInstance() 静态方法返回全局唯一实例。其核心设计特点在于:绝大多数数据成员被声明为 static,这意味着即使不通过 getInstance() 获取实例指针,任何包含 jidu_dataCenter.h 的编译单元都可以直接通过 DataCenter::memberName 访问静态数据。这种设计在便利性和封装性之间做了权衡——它为 jidu_orderInfo.cppjidu_vehicleInfo.cppjidu_client.cpp 等大量直接读取 DataCenter 静态成员的模块提供了零开销的访问路径。

Sources: jidu_dataCenter.h, jidu_dataCenter.h

mermaid
classDiagram
    class DataCenter {
        +static JD_VEHICLE_ORDER_t m_VehicleOrderInfo
        +map~string,JD_ECU_SAFETY_CONSTANT_t~ m_EcuSafetyConstant
        +static JD_EOL_KEY_t m_EolKey
        +static JD_OTA_CERT_t m_OtaCert
        +static map~string,string~ m_aesKey
        +static JD_SummaryData_t m_summaryData
        +static JD_EcuCertInfo_t m_EcuCertInfo
        +static string m_deviceSN
        +static map~string,JD_EcuStatusInfo_t~ m_EcuStatus
        +static string errMsg
        +static string factory
        +static string language
        +static VehicleInfo m_vehicleInfo
        +static JD_ECU_DIAGNOSTIC_INFO_t m_EcuBncmCloudInfo
        +static vector~JD_ECU_DIAGNOSTIC_INFO_t~ m_vecEcuDiagnosticInfo
        +static map~string,vector~JIDU_DTC_INFO_t~~ m_mapDtcDatabase
        +static map~int,CallServerRecord~ m_callServerRecord
        +static vector~EbocInfo~ m_vecEbocInfo
        -static DataCenter* instance
        +static getInstance() DataCenter*
        +reset() void
        +setEcuSafetyConstant(string, JD_ECU_SAFETY_CONSTANT_t) bool
        +getEcuSafetyConstant(string, JD_ECU_SAFETY_CONSTANT_t&) bool
        +getCarConfig(CBinary, VehicleCfg&) bool
        +getCarConfig(CBinary) int
        +getCarConfig(string) int
    }
    class VehicleInfo {
        +CBinary binCCP
        +vector~string~ vecEcuName
        +vector~uint16_t~ vecEcuId
        +string baseLine
        +map~uint16_t,JD_VehicleEcuInfo_t~ mapEcuInfo
        +string tpmsId
        +string batteryRemain
        +string vehicleType
        +int sshStaus
        +int chargingIsOpen
        +int gloveboxIsOpen
        +int powerType
        +int carType
        +int carTypeId
        +int empennage
    }
    class VehicleCfg {
        +float iBatteryCapacity
        +string strMotor
        +string strWpcEcuName
        +string strBecmEcuName
        +string strWpcConfig
        +uint8_t iEmpennage
        +int iPlatformVoltage
        +string strIemEcuName
    }
    class CallServerRecord {
        +string host
        +string uri
        +string method
        +string body
        +string response
    }
    DataCenter --> VehicleInfo
    DataCenter --> CallServerRecord
    DataCenter ..> VehicleCfg

核心数据域详解

DataCenter 的 19 个静态/实例成员覆盖了从云端通信到本地诊断、从刷写前置校验到报告生成的完整数据需求。下面按功能域分类阐述。

车辆订单信息:m_VehicleOrderInfo

类型为 JD_VEHICLE_ORDER_t,是整个插件中最重要的数据结构之一。它存储了从服务器接口 callServer(26)(工厂模式)或 callServer(54)(售后模式)获取的完整车辆订单,包含 VIN、MixNo、CCP 编码、车型、基线版本、软件版本号、EBOC 编码、车辆环境标识 以及 ECU 清单(vecListEcu。每个 ECU 条目(JD_ECU_INFO_t)又包含 ECU ID(十六进制)、ECU 名称、硬件版本号(HWPN)、序列号(DN)以及软件版本号列表(SWPN List)。vecListEcuNew 则是通过 callServer(88) 从车辆软件应用接口获取的新版 ECU 清单,按相同结构存储但来源不同。jidu_orderInfo.cpp 中的所有 get_jd_orderInfo_* 系列函数均以该字段为数据源。

Sources: jidu_macro.h, [jidu_client.cpp](src/jidu_client.cpp#L26-L88 中的 case 26 回调), jidu_orderInfo.cpp

ECU 安全常量:m_EcuSafetyConstant

类型为 map<string, JD_ECU_SAFETY_CONSTANT_t>,以 ECU 名称(如 "BGM"、"CDC"、"TCAM"、"ACU")为键,存储每个 ECU 的四类安全常量:keySwdl(软件下载密钥)、keyImmo(防盗密钥)、keySal(盐值密钥)、keyCommon(通用密钥)。这些常量在诊断安全访问(Security Access)流程中用于 SeedToKey 计算。数据通过 callServer(6)(工厂)或 callServer(59)(售后)从服务器获取 JSON 响应中的 swdlimmosalcommon 四个数组解析填充。注意 m_EcuSafetyConstant 是 DataCenter 中唯一非 static 的 map 型数据成员——它通过 setEcuSafetyConstant()getEcuSafetyConstant() 实例方法访问,而非直接操作。

Sources: jidu_macro.h, [jidu_client.cpp](src/jidu_client.cpp#L6 与 L59 case), jidu_dataCenter.cpp

EOL 密钥:m_EolKey

类型为 JD_EOL_KEY_t,存储下线检测(End-of-Line)所需的密钥集合:各 ECU 的防盗密钥(immoKeyEcmimmoKeyIemimmoKeyMgmimmoKeyRemote)、BNCM/BGM 域控密钥(dkBncmBgm)以及电源根密钥(powerRootKeypowerRootKeyId)。数据通过 callServer(19)(工厂)或 callServer(58)(售后)获取。

Sources: jidu_macro.h, [jidu_client.cpp](src/jidu_client.cpp#L19 与 L58 case)

OTA 证书:m_OtaCert

类型为 JD_OTA_CERT_t,存储 OTA 远程升级所需的 CA 证书(caCert客户端证书(clientCert,均为 Base64 编码字符串。通过 callServer(27)(工厂)或 callServer(64)(售后)获取。在 jidu_orderInfo.cpp 中,get_jd_otaCert_ca()get_jd_otaCert_client() 对其进行 Base64 解码后输出原始二进制。

Sources: jidu_macro.h, jidu_orderInfo.cpp

ECU 证书信息:m_EcuCertInfo

类型为 JD_EcuCertInfo_t,是域控 ECU(TCAM、BGM、CDC、ACU)的证书信息集合。由三部分组成:cls_strEcuCa(ECU CA 证书,Base64)、cls_strVid(车辆 VID,十六进制字符串)以及 ecuCertInfo(以 ECU 类型名为键的 JD_EcuCertItem_t map,每个条目包含 P12 证书、P12 密钥、AES 密钥、SOA 密钥和域控密钥 dvcKey)。数据通过 callServer(20/23)(工厂)或 callServer(56/65)(售后)获取。

Sources: jidu_macro.h, [jidu_client.cpp](src/jidu_client.cpp#L20/23/56/65 case)

AES 密钥映射:m_aesKey

类型为 map<string, string>,以 ECU 名为键存储 AES 密钥字符串。通过 callServer(21)(工厂)或 callServer(55)(售后)获取。特别地,当这些接口返回错误码 9002/9004/9005 时,系统会自动回退到硬编码的默认 AES 密钥\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF 的 Base64 编码),写入 ACU、BGM、CDC、TCAM 四个域控 ECU,确保基础通信能力不中断。

Sources: [jidu_client.cpp](src/jidu_client.cpp#L21/55 case), [jidu_client.cpp](src/jidu_client.cpp#L901-L907 middle fallback logic)

车辆实时信息:m_vehicleInfo

类型为 VehicleInfo,存储从车辆实时读取的状态信息,包括:CCP 原始二进制数据(binCCP)、ECU 名称与 ID 列表、基线版本号、胎压 ID(tpmsId)、电池剩余电量(batteryRemain,默认 "未知")、车型(vehicleType,默认 "MarsOne")、SSH 状态、充电口状态、手套箱状态、高压平台电压类型(powerType,来自 CCP#962)、车型编码(carType 来自 CCP#950、carTypeId 来自 CCP#966/967)以及尾翼配置(empennage 来自 CCP#564)。这些数据通过 set_jd_vehicleInfo_* 系列 API 从 OTX 脚本层写入。

Sources: jidu_dataCenter.h

ECU 状态跟踪:m_EcuStatus

类型为 map<string, JD_EcuStatusInfo_t>,以 ECU 名称为键,存储每个 ECU 的三维状态:ECU 状态(未配置/离线/在线/需升级/硬件不匹配/软件不匹配/刷写条件不满足)、FOTA 状态(无结果/离线/硬件错误/升级失败/升级成功/选装件)以及 配置状态(未安装/高配/低配)。这些状态在刷写前置检查和报告生成中被大量引用。

Sources: jidu_macro.h

其他全局状态

字段类型用途填充来源
m_deviceSNstring诊断设备序列号set_jd_deviceSn() API 或 pver 配置文件
errMsgstring最近一次 callServer 的错误消息JiduClient::callServer() 失败路径
factorystring工厂标识("PMA" 或 "DMA"),决定服务器环境路由setFactory() API
languagestring界面语言(默认 "zh-CN"),作为 API 请求参数setLanguage() API
m_summaryDataJD_SummaryData_t工位测试汇总结果callServer(28)
m_callServerRecordmap<int, CallServerRecord>按请求类型索引的服务器调用完整记录(host/uri/method/body/response)每次 callServer 自动记录
m_vecEbocInfovector<EbocInfo>EBOC 特性配置信息列表callServer(79)
m_EcuBncmCloudInfoJD_ECU_DIAGNOSTIC_INFO_tBNCM 云端诊断指令信息callServer(29/67) 上传后缓存
m_vecEcuDiagnosticInfovector<JD_ECU_DIAGNOSTIC_INFO_t>各 ECU 诊断指令信息集合jd_add_ecuDiagnosticInfo() 累积
m_mapDtcDatabasemap<string, vector<JIDU_DTC_INFO_t>>以 ECU 名为键的 DTC 故障码数据库配置文件加载

Sources: jidu_dataCenter.h, jidu.cpp

车辆配置解析:getCarConfig 方法

getCarConfig 是 DataCenter 中最具业务逻辑深度的方法,它从原始 CCP(Car Configuration Parameter)二进制数据中解析出车辆的完整硬件配置。提供三个重载版本:

重载签名返回值含义
完整配置版getCarConfig(CBinary ccp, VehicleCfg& cfg)成功返回 true,填充完整的 VehicleCfg 结构
电池容量版getCarConfig(CBinary ccp)返回电池容量(kWh),失败返回 -1
字符串适配版getCarConfig(string ccp)将十六进制 CCP 字符串转为 CBinary 后委托给电池容量版

完整配置版的解析逻辑分五个维度,所有解析前提是 CCP 数据长度超过 1500 字节

  1. 电池容量与电机类型:通过 CCP[2](索引从 0 开始,对应 CCP#3)判定电机配置(0x81 = 单电机,0x80 = 双电机),通过 CCP[565](对应 CCP#566)判定电池容量(0x17 = 75kWh,0x10 = 102kWh,0x18 = 76kWh,0x19 = 98kWh)。三种车型组合分别为 标续版(单电机 + 75kWh)、长续版(单电机 + 102kWh)、性能版(双电机 + 102kWh)。

  2. 尾翼配置CCP[563](对应 CCP#564),0x01 = 低配无主动尾翼,0x02 = 高配有尾翼。

  3. 无线充电配置CCP[449](对应 CCP#450),1–5 对应五种配置组合(无 NFC 无 WPC / 仅 NFC / 仅 WPC / NFC+WPC / NFC+双 WPC),并据此确定 WPC ECU 名称为 "WPC""WPC2"

  4. 高压平台电压CCP[961](对应 CCP#962),0x00 = 400V,0x02 = 800V。

  5. IEM 电机控制器型号:遍历 m_VehicleOrderInfo.vecListEcu,根据 IEM 的 ECU ID 判定——0x5071 = IEM_IGBT,0x5072 = IEM_SIC,其他 = IEM2。

电池容量版重载额外处理了 0x18(76kWh)和 0x19(98kWh)两种扩展电池类型——这些在完整配置版中会落入 else 分支返回默认值 98kWh。

Sources: jidu_dataCenter.cpp

mermaid
flowchart TD
    A[CCP 二进制数据] --> B{长度 > 1500?}
    B -->|否| C[Tracer::error 并返回 false/-1]
    B -->|是| D[CCP#3: 电机类型]
    D --> E[CCP#566: 电池容量]
    E --> F{组合判断}
    F -->|0x81 + 0x17| G[标续版: 75kWh 单电机]
    F -->|0x81 + 0x10| H[长续版: 102kWh 单电机]
    F -->|0x80 + 0x10| I[性能版: 102kWh 双电机]
    F -->|其他| J[默认: 98kWh 双电机]
    G & H & I & J --> K[CCP#564: 尾翼配置]
    K --> L[CCP#450: WPC 充电配置]
    L --> M[CCP#962: 高压平台电压]
    M --> N[遍历 vecListEcu 判定 IEM 型号]
    N --> O[填充 VehicleCfg 并返回]

ECU 安全常量查找机制:命名回退链

getEcuSafetyConstant() 方法实现了一个多级 ECU 名称回退(fallback)策略。当传入的 ECU 名称在 m_EcuSafetyConstant map 中精确匹配失败时,方法会依次应用以下规则:

规则触发条件回退为
IEM 前缀匹配名称以 "IEM" 开头"IEM"
BECM 前缀匹配名称以 "BECM" 开头"BECM1"
WPC 前缀匹配(排除 WPC3)名称以 "WPC" 开头且不等于 "WPC3""WPC"
RCML 前缀匹配名称以 "RCML" 开头"RCML"
RCMR 前缀匹配名称以 "RCMR" 开头"RCMR"
RCMM 前缀匹配名称以 "RCMM" 开头"RCMM"
MGM 前缀匹配名称以 "MGM" 开头"MGM"
电压后缀剥离名称以 "_400V""_800V" 结尾去掉后缀(如 "BECM1_400V""BECM1"

这种设计使得调用方可以传入带有配置后缀的 ECU 名称(如 "IEM_IGBT""BECM1_102"),而 DataCenter 内部自动将其映射到基础 ECU 类型的安全常量条目,避免为每个变体重复存储相同的安全密钥。注意 setEcuSafetyConstant() 方法始终返回 false(疑似未完成实现),但数据实际已被写入 map 中。

Sources: jidu_dataCenter.cpp

数据填充流程:JiduClient 后处理回调

DataCenter 中绝大多数数据并非主动拉取,而是通过 JiduClient::callServer_affterHandler() 在服务器请求成功后被动填充。该函数内部有一个巨大的 switch (iType) 分支,根据请求类型编号将 JSON 响应解析并写入 DataCenter 的对应静态字段。下表梳理主要映射关系:

iType前置清理(preHandler)后置填充目标(affterHandler)说明
1m_VehicleOrderInfo.strCCPCode / strVehicleType获取 CCP 编码或车型
4清空 strTpmsIdstrTpmsSupplierIdm_VehicleOrderInfo.strTpmsId / strTpmsSupplierId获取胎压 ID
6 / 59清空 m_EcuSafetyConstantm_EcuSafetyConstant(逐 ECU 填充四类密钥)安全常量(工厂/售后)
11 / 19 / 57 / 58清空 m_EolKey 各字段m_EolKey(七个子密钥)EOL 密钥
20 / 23 / 56 / 65清空 m_EcuCertInfom_EcuCertInfo(ecuCa、vid、ecuCertInfo)ECU 证书信息
21 / 55清空 m_aesKeym_aesKey(逐 ECU 填充 AES 密钥)AES 密钥
26部分清空 m_VehicleOrderInfom_VehicleOrderInfo(完整订单 + clearDataCenterCache()工厂订单信息
27 / 64清空 m_OtaCertm_OtaCert(caCert + clientCert)OTA 证书
28m_summaryData(完整工位测试结果树)工位测试汇总
51清空 strSwpnm_VehicleOrderInfo.strSwpn售后软件版本
53m_VehicleOrderInfo.strCCPCode售后 CCP
54清空 vecListEcum_VehicleOrderInfo.vecListEcu(含 ECU ID→名称映射)售后 ECU 清单
68m_VehicleOrderInfo.strCCPCodeCCP 任务号查询附带
79清空 m_vecEbocInfom_vecEbocInfo(完整 EBOC 列表)EBOC 特性
88清空 vecListEcuNewm_VehicleOrderInfo.vecListEcuNew新版 ECU 清单

关键设计原则:每个 callServer 请求类型在 preHandler 中会先清空对应的 DataCenter 字段,然后发起 HTTP 请求,成功后在 affterHandler 中重新填充。这确保了每次调用都基于最新的服务器数据,避免残留旧数据造成业务逻辑错误。同时 m_callServerRecord[iType] 会在请求过程中自动记录完整的请求/响应信息,为问题排查提供审计追踪能力。

Sources: [jidu_client.cpp](src/jidu_client.cpp#L650-L820 preHandler), [jidu_client.cpp](src/jidu_client.cpp#L822-L1120 affterHandler)

跨模块交互关系

DataCenter 作为全局数据中枢,与几乎所有核心模块都存在数据依赖关系:

mermaid
flowchart LR
    subgraph 云端通信层
        JC[JiduClient]
    end
    subgraph DataCenter
        DC[DataCenter 单例]
    end
    subgraph 数据消费层
        OI[jidu_orderInfo.cpp<br/>订单信息查询 API]
        VI[jidu_vehicleInfo.cpp<br/>车辆信息查询 API]
        FL[jidu_flasher.cpp<br/>刷写任务编排]
        DT[jidu_dtc.cpp<br/>DTC 故障码管理]
        RP[jidu_report.cpp<br/>诊断报告生成]
    end
    subgraph 基础设施层
        EV[EnvConfig<br/>环境配置]
        VC[CVehicleConfig<br/>整车软件包配置]
    end

    JC -->|callServer_affterHandler 填充| DC
    JC -->|读取 factory/language/deviceSN| DC
    OI -->|读取 m_VehicleOrderInfo / m_vecEbocInfo / m_EcuCertInfo / m_OtaCert / m_EolKey / m_aesKey / m_deviceSN| DC
    VI -->|读取 m_vehicleInfo / m_VehicleOrderInfo| DC
    FL -->|读取 m_EcuStatus / m_vehicleInfo / m_VehicleOrderInfo| DC
    DT -->|读取 m_mapDtcDatabase| DC
    RP -->|读取 m_summaryData / m_callServerRecord| DC
    EV -->|读取 factory| DC
    VC -->|读取 m_VehicleOrderInfo| DC
  • JiduClient 是数据的写入者:每次 callServer 成功后通过 affterHandler 填充 DataCenter 的对应字段,同时也从 DataCenter 读取 factory(用于服务器环境路由选择)、language(作为 API 查询参数)、m_deviceSN(用于请求签名和设备标识)、m_vehicleInfo.powerTypem_vehicleInfo.carTypeId(用于 PKI 接口请求参数补充)。
  • jidu_orderInfo.cpp 是最大的读取者:其所有 get_jd_orderInfo_* API 函数均直接引用 DataCenter::m_VehicleOrderInfo 的静态成员,提供 VIN、CCP、ECU 清单、软件版本、EBOC 等查询能力。
  • jidu_vehicleInfo.cpp 同时依赖 DataCenter 的 m_vehicleInfo(实时车辆状态)和 m_VehicleOrderInfo(服务器订单),并在 get_jd_ecuName_byIpAddr() 中调用 getCarConfig() 来解析车辆配置以确定正确的 ECU 名称变体。
  • jidu_flasher.cpp 通过 DataCenter::m_EcuStatus 跟踪每个 ECU 的刷写状态(在线/离线/需升级等),通过 m_vehicleInfo 判断高压平台,通过 m_VehicleOrderInfo 获取订单 ECU 清单。
  • setFactory() 是 DataCenter 初始化的关键入口:它不仅设置 DataCenter::factory,还触发 JiduClient::loadEnvirment()loadParam() 以重新加载对应工厂环境的服务器地址和证书,以及初始化 CVehicleConfig 单例。

Sources: jidu.cpp, [jidu_client.cpp](src/jidu_client.cpp#L293-L310 diag URL 构造), jidu_vehicleInfo.cpp

设计评注与潜在改进点

DataCenter 的设计体现了典型的全局状态容器(God Object) 模式,在嵌入式诊断工具的场景下具有快速开发和低访问成本的优点,但也存在几个需要注意的设计特征:

  • 静态成员与实例成员混用m_EcuSafetyConstant 是唯一的非 static 数据成员,需要通过 getInstance()->setEcuSafetyConstant() 访问,而其他所有静态成员可直接通过 DataCenter:: 访问。这种不一致可能导致新开发者困惑。
  • setEcuSafetyConstant() 返回值语义异常:方法体内执行了赋值操作后始终 return false,这可能是一个未完成的实现或故意的标记。
  • reset() 的覆盖范围有限:当前仅清理 m_vehicleInfo.mapEcuInfovecEcuNamevecEcuNameOrderByInitial,但 clearDataCenterCache()callServer(26) 时调用 reset() 后还需结合 preHandler 中的字段级清理来完成完整的数据刷新。

Sources: jidu_dataCenter.cpp, jidu_dataCenter.cpp

延伸阅读

理解 DataCenter 的数据来源后,建议按以下路径深入: