Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

4.7 DSP——数据读取(0x22与0x2E的DID查找与信号读写)

DID不是一个简单的地址——它是一个递归结构

Arctic Core的DID配置不是“DID→dataRecord“的简单键值对。一个DID由DID引用链组成——每个DID可以递归包含其他DID。readDidData()是递归遍历这个图的函数。


DID配置结构

typedef struct {
    uint16 DspDidIdentifier;            // DID编号 (如 0xF190)
    uint32 DspDidDataByteSize;          // 总数据长度
    boolean DspDidDynamicllyDefined;    // 是否动态DID
    Dcm_DspDidInfoType DspDidInfo;      // 读写权限、会话/安全需求
    Dcm_DspDidRefType DspDidRef;        // 子信号引用表 (EOL终止)
} Dcm_DspDidType;

typedef struct {
    uint8 DspDidRefType;   // DATA_PORT_SYNCH / ASYNCH / ECU_SIGNAL / NVM_BLOCK
    union {
        struct { Dcm_SynchDataReadFncType SynchDataReadFnc; ... } synch;
        struct { Dcm_AsynchDataReadFncType AsynchDataReadFnc; ... } asynch;
        struct { Dcm_SRDataReadFncType SRDataReadFnc; ... } sr;
        struct { uint16 NvMBlockId; ... } nvm;
    } data;
    uint16 DspDidRefBitPosition;       // 在DID数据内的起始bit位置
    uint16 DspDidRefBitLength;         // 信号bit长度
    uint8  DspDidRefEndianess;         // BIG_ENDIAN / LITTLE_ENDIAN
} Dcm_DspDidRefType;

getDidData —— 四种端口类型

static Std_ReturnType getDidData(
    Dcm_DspDidType *did, uint8 *txBuf, uint16 *txPos, ...)
{
    // 1. 写入DID头 (2字节+数据)
    if (includeDID) {
        txBuf[(*txPos)++] = (did->DspDidIdentifier >> 8) & 0xFF;
        txBuf[(*txPos)++] = did->DspDidIdentifier & 0xFF;
    }

    // 2. 遍历DID引用表
    Dcm_DspDidRefType *ref = did->DspDidRef;
    while (ref->DspDidRefType != Arc_EOL) {

        switch (ref->DspDidRefType) {

        case DATA_PORT_SYNCH:  // 同步数据端口
            // 立即回调读取数据——无延迟
            ref->data.synch.SynchDataReadFnc(
                &txBuf[*txPos], ref->DspDidRefBitLength);
            break;

        case DATA_PORT_ASYNCH: // 异步数据端口
            opStatus = DCM_READ_OK;
            ref->data.asynch.AsynchDataReadFnc(
                &txBuf[*txPos], ref->DspDidRefBitLength, &opStatus);
            if (opStatus == DCM_READ_PENDING) {
                return E_PENDING;  // 等下次MainFunction再取
            }
            break;

        case DATA_PORT_ECU_SIGNAL: // SR端口 (Sender/Receiver)
            ReadSRSignal(ref->DspDidRefBitPosition,
                         ref->DspDidRefBitLength,
                         txBuf);
            break;

        case DATA_PORT_BLOCK_ID: // NvM块
            NvM_ReadBlock(ref->data.nvm.NvMBlockId, &txBuf[*txPos]);
            break;
        }
        *txPos += ref->DspDidRefBitLength / 8;
        ref++;
    }
    return E_OK;
}

核心洞察:四种端口类型映射了ECU中数据的四种来源——SYNCH=RTE同步端口(实时信号)、ASYNCH=RTE异步端口(可能需要等待)、ECU_SIGNAL=CDD传感器信号(直读)、NVM_BLOCK=非易失存储块。DSP不需要知道每个信号的物理地址——它只知道该调用什么回调。


ReadSRSignal —— 位级别的信号提取

static void ReadSRSignal(uint16 bitPosition, uint16 bitLength,
                         uint8 *dataBuffer)
{
    // 读取原始字节
    uint8 rawBuffer[DCM_MAX_SR_SIGNAL_BYTES];
    DspDataReadDataFnc.SRDataReadFnc(rawBuffer, bitPosition, bitLength);

    // 处理大小端转换
    if (endianess == LITTLE_ENDIAN) {
        // 从rawBuffer按小端序解包到dataBuffer
        unpackLittleEndian(rawBuffer, dataBuffer, bitLength);
    } else {
        unpackBigEndian(rawBuffer, dataBuffer, bitLength);
    }
}

DID递归引用——复合DID

一个DID可以引用另一个DID:

static Std_ReturnType readDidData(Dcm_DspDidType *did, ...) {
    Dcm_DspDidRefType *ref = did->DspDidRef;
    while (ref->DspDidRefType != Arc_EOL) {
        if (ref->DspDidRefType == DATA_PORT_DID_REF) {
            // 递归:引用了另一个DID
            Dcm_DspDidType *subDid = lookupNonDynamicDid(ref->refDid);
            readDidData(subDid, txBuf, txPos, ...);  // 递归
        } else {
            getDidData(did, txBuf, txPos, ...);  // 直接读信号
        }
        ref++;
    }
}

0x2E写入的对称实现

写入和读取使用同一套DID配置——区别在回调方向:

// 写SR信号
static void WriteSRSignal(uint16 bitPos, uint16 bitLen, uint8 *data) {
    uint8 rawBuffer[DCM_MAX_SR_SIGNAL_BYTES];
    // 先把数据包成对应大小端格式
    if (endianess == LITTLE_ENDIAN) {
        packLittleEndian(data, rawBuffer, bitLen);
    } else {
        packBigEndian(data, rawBuffer, bitLen);
    }
    // 回调写入
    DspDataWriteDataFnc.SRDataWriteFnc(rawBuffer, bitPos, bitLen);
}

本篇小结

  1. DID配置是一个递归引用图——每个DID可以包含任意数量的信号引用或子DID引用。
  2. 四种端口类型(SYNCH/ASYNCH/ECU_SIGNAL/NVM_BLOCK)覆盖了ECU中数据的全部来源——DSP不关心物理地址,只驱动回调。
  3. 位级别的信号提取通过ReadSRSignal和WriteSRSignal实现——支持大端和小端两种字节序。
  4. 异步端口(ASYNCH)通过E_PENDING+断点重入实现跨MainFunction周期的数据获取。

【下集预告】:DID读完了——现在我们去看DTC的读取接口和上传下载的blockSequenceCounter流水线。0x19如何调用DEM的API获取筛选后的DTC列表?0x34→0x36→0x37的TransferStatus状态机在DSP中怎么运作?