You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vanetza中Cpm消息嵌套SEQUENCE OF数据填充与编解码问题排查

Vanetza开发CPM消息:编码成功但解码失败的问题排查与修复

我正在使用Vanetza开发CPM消息,已通过ASN.1生成对应的C/C++文件,消息结构体完全遵循ASN.1定义。其中PerceptionDataContainer是SEQUENCE OF PerceptionData类型,每个PerceptionData包含的PerceivedObjectContainer又是SEQUENCE OF PerceivedObject类型。我编写了数据填充代码,目前编码成功但解码失败,数据填充逻辑可能存在问题,附上相关代码与结构体定义,请求正确的实现方式。

数据填充代码

vanetza::asn1::Cpm cpm;

auto object = asn1::allocate<PerceivedObject_t>(); //this fill the struct PerceivedObject with basic info
auto perception = asn1::allocate<PerceptionData_t>();

PerceivedObject *arrayobjeto[2];

cpm->cpm.cpmParameters.perceptionData = asn1::allocate<CpmParameters::CpmParameters__perceptionData>();

cpm->header.protocolVersion=2;
cpm->header.messageID=ItsPduHeader__messageID_cpm;
cpm->header.stationID=1;
cpm->cpm.cpmParameters.managementContainer.stationType=2;

for(int i=0; i<2;i++) {
    arrayobjeto[i]=asn1::allocate<PerceivedObject>();
    arrayobjeto[i]->objectID= i+1;
    arrayobjeto[i]->timeOfMeasurement = TimeOfMeasurement_oneMilliSecond;
    arrayobjeto[i]->xDistance.value = DistanceValue_oneMeter;
    arrayobjeto[i]->xDistance.confidence = DistanceConfidence_oneMeter;
    arrayobjeto[i]->yDistance.value = DistanceValue_oneMeter;
    arrayobjeto[i]->yDistance.confidence = DistanceConfidence_oneMeter;
    arrayobjeto[i]->xSpeed.value = SpeedValueExtended_oneCentimeterPerSec;
    arrayobjeto[i]->xSpeed.confidence = SpeedConfidence_equalOrWithinOneMeterPerSec;
    arrayobjeto[i]->ySpeed.value = SpeedValueExtended_oneCentimeterPerSec;
    arrayobjeto[i]->ySpeed.confidence = SpeedConfidence_equalOrWithinOneMeterPerSec;
}
perception->containerId=1;
perception->containerData.present=PerceptionData__containerData_PR_PerceivedObjectContainer;
perception->containerData.choice.PerceivedObjectContainer.numberOfPerceivedObjects=1;

for(int i=0; i<2;i++) {
    EXPECT_EQ(0, ASN_SEQUENCE_ADD(&perception->containerData.choice.PerceivedObjectContainer.perceivedObjects,arrayobjeto[i]));
}
EXPECT_EQ(0, ASN_SEQUENCE_ADD(&cpm->cpm.cpmParameters.perceptionData->list, perception));
EXPECT_EQ(1, cpm->cpm.cpmParameters.perceptionData->list.count);
EXPECT_EQ(2, cpm->cpm.cpmParameters.perceptionData->list.array[0]->containerData.choice.PerceivedObjectContainer.perceivedObjects.list.count);
EXPECT_EQ(perception, cpm->cpm.cpmParameters.perceptionData->list.array[0]);
EXPECT_EQ(arrayobjeto[0], cpm->cpm.cpmParameters.perceptionData->list.array[0]->containerData.choice.PerceivedObjectContainer.perceivedObjects.list.array[0]);


EXPECT_TRUE(cpm.validate());
EXPECT_FALSE(cpm.encode().empty());
ByteBuffer buffer = cpm.encode();
std::cout << "tamaño: " << buffer.size() << "\n";
for (const auto byte:buffer){
    printf("%02x ",byte);
}

ASSERT_TRUE(cpm.decode(buffer));
std::cout << cpm.size();

结构体定义

typedef struct CpmParameters {
    CpmManagementContainer_t     managementContainer;
    struct OriginatingStationData   *stationDataContainer;  /* OPTIONAL */
    struct CpmParameters__perceptionData {
        A_SEQUENCE_OF(struct PerceptionData) list;
        
        /* Context for parsing across buffer boundaries */
        asn_struct_ctx_t _asn_ctx;
    } *perceptionData;

....

typedef struct PerceptionData {
    CpmContainerId_t     containerId;
    struct PerceptionData__containerData {
        PerceptionData__containerData_PR present;
        union PerceptionData__containerData_u {
            SensorInformationContainer_t     SensorInformationContainer;
            PerceivedObjectContainer_t   PerceivedObjectContainer;
            FreeSpaceAddendumContainer_t     FreeSpaceAddendumContainer;
        } choice;
        
        /* Context for parsing across buffer boundaries */
        asn_struct_ctx_t _asn_ctx;
    } containerData;

....

typedef struct PerceivedObjectContainer {
    NumberOfPerceivedObjects_t   numberOfPerceivedObjects;  /* DEFAULT 0 */
    struct PerceivedObjectContainer__perceivedObjects {
        A_SEQUENCE_OF(struct PerceivedObject) list;
        
        /* Context for parsing across buffer boundaries */
        asn_struct_ctx_t _asn_ctx;
    } perceivedObjects;
    
    /* Context for parsing across buffer boundaries */
    asn_struct_ctx_t _asn_ctx;
} PerceivedObjectContainer_t;

问题排查与修复方案

核心问题1:numberOfPerceivedObjects与实际序列长度不匹配

你设置了perception->containerData.choice.PerceivedObjectContainer.numberOfPerceivedObjects=1,但实际通过ASN_SEQUENCE_ADD添加了2个PerceivedObject实例。ASN.1解码时会校验这个字段值和序列实际元素数量是否一致,不匹配会直接导致解码失败。

核心问题2:SEQUENCE容器未初始化

Vanetza的asn1::allocate仅分配内存,不会自动初始化ASN.1的SEQUENCE结构体(比如list.count和list.array的初始状态)。使用ASN_SEQUENCE_ADD前必须调用asn_sequence_init初始化容器,否则可能导致内存异常或编码/解码不一致。

修复后的代码示例

vanetza::asn1::Cpm cpm;

auto perception = asn1::allocate<PerceptionData_t>();
PerceivedObject *arrayobjeto[2];

// 初始化perceptionData的SEQUENCE容器
cpm->cpm.cpmParameters.perceptionData = asn1::allocate<CpmParameters::CpmParameters__perceptionData>();
asn_sequence_init(&cpm->cpm.cpmParameters.perceptionData->list);

// 填充头部和管理容器
cpm->header.protocolVersion=2;
cpm->header.messageID=ItsPduHeader__messageID_cpm;
cpm->header.stationID=1;
cpm->cpm.cpmParameters.managementContainer.stationType=2;

// 创建并填充2个PerceivedObject
for(int i=0; i<2;i++) {
    arrayobjeto[i]=asn1::allocate<PerceivedObject>();
    arrayobjeto[i]->objectID= i+1;
    arrayobjeto[i]->timeOfMeasurement = TimeOfMeasurement_oneMilliSecond;
    arrayobjeto[i]->xDistance.value = DistanceValue_oneMeter;
    arrayobjeto[i]->xDistance.confidence = DistanceConfidence_oneMeter;
    arrayobjeto[i]->yDistance.value = DistanceValue_oneMeter;
    arrayobjeto[i]->yDistance.confidence = DistanceConfidence_oneMeter;
    arrayobjeto[i]->xSpeed.value = SpeedValueExtended_oneCentimeterPerSec;
    arrayobjeto[i]->xSpeed.confidence = SpeedConfidence_equalOrWithinOneMeterPerSec;
    arrayobjeto[i]->ySpeed.value = SpeedValueExtended_oneCentimeterPerSec;
    arrayobjeto[i]->ySpeed.confidence = SpeedConfidence_equalOrWithinOneMeterPerSec;
}

// 配置PerceptionData
perception->containerId=1;
perception->containerData.present=PerceptionData__containerData_PR_PerceivedObjectContainer;
// 初始化PerceivedObjectContainer的SEQUENCE容器
asn_sequence_init(&perception->containerData.choice.PerceivedObjectContainer.perceivedObjects);
// 设置正确的对象数量
perception->containerData.choice.PerceivedObjectContainer.numberOfPerceivedObjects=2;

// 添加PerceivedObject到序列
for(int i=0; i<2;i++) {
    EXPECT_EQ(0, ASN_SEQUENCE_ADD(&perception->containerData.choice.PerceivedObjectContainer.perceivedObjects, arrayobjeto[i]));
}

// 添加PerceptionData到序列
EXPECT_EQ(0, ASN_SEQUENCE_ADD(&cpm->cpm.cpmParameters.perceptionData->list, perception));

// 验证逻辑保持不变
EXPECT_EQ(1, cpm->cpm.cpmParameters.perceptionData->list.count);
EXPECT_EQ(2, cpm->cpm.cpmParameters.perceptionData->list.array[0]->containerData.choice.PerceivedObjectContainer.perceivedObjects.list.count);
EXPECT_EQ(perception, cpm->cpm.cpmParameters.perceptionData->list.array[0]);
EXPECT_EQ(arrayobjeto[0], cpm->cpm.cpmParameters.perceptionData->list.array[0]->containerData.choice.PerceivedObjectContainer.perceivedObjects.list.array[0]);

EXPECT_TRUE(cpm.validate());
EXPECT_FALSE(cpm.encode().empty());
ByteBuffer buffer = cpm.encode();
std::cout << "tamaño: " << buffer.size() << "\n";
for (const auto byte:buffer){
    printf("%02x ",byte);
}

ASSERT_TRUE(cpm.decode(buffer));
std::cout << cpm.size();

额外注意事项

  • 确保所有ASN.1 SEQUENCE类型的容器都已通过asn_sequence_init初始化,避免未定义行为。
  • 可选字段(如stationDataContainer)如果不需要使用,保持为NULL即可,ASN.1编码器会自动忽略。
  • 调用cpm.validate()时如果返回false,可以打印详细的错误信息(Vanetza的ASN.1封装通常支持获取验证日志),进一步定位字段填充问题。

内容的提问来源于stack exchange,提问作者Santiago

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 16:05:47