分解具有特定结构的原始字节字符串会给出错误的数据

Breaking down raw byte string with particular structure gives wrong data

我正在使用一个基于 32 位 ARM Cortex-M3 的 ZigBee 模块。但我的问题与 ZigBee 协议本身无关。我只能访问应用层的源代码,这足以满足我的目的。下层 (APS) 将数据传递到 APSDE-DATA.indication 原语中的应用层到以下应用函数:

void zbpro_dataRcvdHandler(zbpro_dataInd_t *data)
{
    DEBUG_PRINT(DBG_APP,"\n[APSDE-DATA.indication]\r\n");

    /* Output of raw bytes string for further investigation.
    *  Real length is unknown, 50 is approximation.
    */
    DEBUG_PRINT(DBG_APP,"Raw data: \n");
    DEBUG_PRINT(DBG_APP,"----------\n");
    for (int i = 0; i < 50; i++){
        DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data+i));
    }
    DEBUG_PRINT(DBG_APP,"\n");

    /* Output of APSDE-DATA.indication primitive field by field */
    DEBUG_PRINT(DBG_APP,"Field by field: \n");
    DEBUG_PRINT(DBG_APP,"----------------\n");
    DEBUG_PRINT(DBG_APP,"Destination address: ");
    for (int i = 0; i < 8; i++)
        DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->dstAddress.ieeeAddr[i]));
    DEBUG_PRINT(DBG_APP,"\n");
    DEBUG_PRINT(DBG_APP,"Destination address mode: 0x%02x\r\n",*((uint8_t*)data->dstAddrMode));
    DEBUG_PRINT(DBG_APP,"Destination endpoint: 0x%02x\r\n",*((uint8_t*)data->dstEndPoint));
    DEBUG_PRINT(DBG_APP,"Source address mode: 0x%02x\r\n",*((uint8_t*)data->dstAddrMode));
    DEBUG_PRINT(DBG_APP,"Source address: ");
    for (int i = 0; i < 8; i++)
        DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->srcAddress.ieeeAddr[i]));
    DEBUG_PRINT(DBG_APP,"\n");
    DEBUG_PRINT(DBG_APP,"Source endpoint: 0x%02x\r\n",*((uint8_t*)data->srcEndPoint));
    DEBUG_PRINT(DBG_APP,"Profile Id: 0x%04x\r\n",*((uint16_t*)data->profileId));
    DEBUG_PRINT(DBG_APP,"Cluster Id: 0x%04x\r\n",*((uint16_t*)data->clusterId));
    DEBUG_PRINT(DBG_APP,"Message length: 0x%02x\r\n",*((uint8_t*)data->messageLength));
    DEBUG_PRINT(DBG_APP,"Flags: 0x%02x\r\n",*((uint8_t*)data->flags));
    DEBUG_PRINT(DBG_APP,"Security status: 0x%02x\r\n",*((uint8_t*)data->securityStatus));
    DEBUG_PRINT(DBG_APP,"Link quality: 0x%02x\r\n",*((uint8_t*)data->linkQuality));
    DEBUG_PRINT(DBG_APP,"Source MAC Address: 0x%04x\r\n",*((uint16_t*)data->messageLength));    
    DEBUG_PRINT(DBG_APP,"Message: ");

    for (int i = 0; i < 13; i++){
        DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->messageContents+i));
    }
    DEBUG_PRINT(DBG_APP,"\n");

    bufm_deallocateBuffer((uint8_t *)data, CORE_MEM);
}

APSDE-DATA.indication原语通过以下结构实现:

/**
 *  @brief type definition for address (union of short address and extended address)
 */
typedef union zbpro_address_tag {
    uint16_t shortAddr;
    uint8_t ieeeAddr[8];
} zbpro_address_t;

/**
 *  @brief apsde data indication structure
 */
PACKED struct zbpro_dataInd_tag {
    zbpro_address_t dstAddress;
    uint8_t dstAddrMode;
    uint8_t dstEndPoint;
    uint8_t srcAddrMode;
    zbpro_address_t srcAddress;
    uint8_t srcEndPoint;
    uint16_t profileId;
    uint16_t clusterId;
    uint8_t messageLength;
    uint8_t flags; /* bit0: broadcast or not; bit1: need aps ack or not; bit2: nwk key used; bit3: aps link key used */
    uint8_t securityStatus; /* not-used, reserved for future */
    uint8_t linkQuality;
    uint16_t src_mac_addr;
    uint8_t messageContents[1];
};
typedef PACKED struct zbpro_dataInd_tag zbpro_dataInd_t;

结果我接下来收到:

[APSDE-DATA.indication]

Raw data:
---------
00 00 00 72 4c 19 40 00 02 e8 03 c2 30 02 fe ff 83 0a 00 e8 05 c1 11 00 11 08 58 40 72 4c ae 53 4d 3f 63 9f d8 51 da ca 87 a9 0b b3 7b 04 68 ca 87 a9

Field by field:
---------------
Destination address: 00 00 00 28 fa 44 34 00
Destination address mode: 0x12
Destination endpoint: 0xc2
Source address mode: 0x12
Source address: 13 01 12 07 02 bd 02 00
Source endpoint: 0xc2
Profile Id: 0xc940
Cluster Id: 0x90a0
Message length: 0x00
Flags: 0x00
Security status: 0x04
Link quality: 0x34
Source MAC Address: 0x90a0
Message: ae 53 4d 3f 63 9f d8 51 da ca 87 a9 0b

从这个输出中我可以看出,虽然原始字符串有一些预期值,但分派的字段完全不同。这种行为的原因是什么以及如何解决?它与 ARM 体系结构或错误的类型转换有某种关系吗?

我无法访问 DEBUG_PRINT 的实现,但我们可以假设它可以正常工作。

您的 DEBUG_PRINT 语句中无需取消引用,例如

DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->dstAddress.ieeeAddr[i]));

应该是

DEBUG_PRINT(DBG_APP,"%02x ", data->dstAddress.ieeeAddr[i]);

等等……

考虑这段代码:

    DEBUG_PRINT(DBG_APP,"%02x ",*((uint8_t*)data->dstAddress.ieeeAddr[i]));

数组下标以及直接和间接成员访问的优先级高于强制转换,因此第三个参数等同于

*( (uint8_t*) (data->dstAddress.ieeeAddr[i]) )

但是data->dstAddress.ieeeAddr[i]不是一个指针,它是一个uint8_t。 C允许你通过强制转换将其转换为指针,但结果不是指针的值,而是指针解释of的价值。取消引用它会产生未定义的行为。

这同样适用于您的其他 DEBUG_PRINT() 个电话。