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
相关产品推荐
相关产品推荐

