riebl / vanetza

Open-source implementation of the ETSI C-ITS protocol stack
Other
200 stars 158 forks source link

How to code a SEQUENCE OF inside a SEQUENCE OF (asn1 to c) #168

Open Santiago1969 opened 1 year ago

Santiago1969 commented 1 year ago

I'm working with vanetza to make cpms messages, I have built the .c and .cpp files from the asn1, so the structures of the message have the structure of the asn1. I have a structure (PerceptionDataContainer) which is a SEQUENCE OF PerceptionData, the Sequence of is a special type of list. Each PerceptionData have a perceivedobjects structure which is a SEQUENCE OF PerceivedObject struct, I have made this code to add information to these struct;

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();

The definitions of the structs are these:

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;

I have reached a good encode but it can not be decode correctly and it seems I have loaded the data into the structs not perfectly, anyone knows how to do it correctly?

When I encode in vanetza the data it does a solution like this: 02 0e 00 00 00 01 00 00 20 13 5a 4e 90 06 b4 9d 20 00 00 00 00 00 18 6a 00 00 01 24 80 80 80 00 00 57 75 03 82 64 40 e0 99 20 00 63 80 01 8c 00 00 04 bb a8 1c 13 22 07 04 c9 00 03 1c 00 0c 60 But when I try to decode it it return false, (can't decode correctly the message) When I don't include the fields of the SEQUENCE OFs it encodes and decodes correctly

riebl commented 1 year ago

Hi @Santiago1969,

if I remember corretly, you should pass perceptionData instead of perceptionData->list to ASN_SEQUENCE_ADD: EXPECT_EQ(0, ASN_SEQUENCE_ADD(cpm->cpm.cpmParameters.perceptionData, perception)); Unfortunately, the whole ASN.1 code is plain C, and thus the void* types accept any pointer type. One has to be extremely careful there and the compiler will just silently accept faulty code.

Santiago1969 commented 1 year ago

Hi Raphael,

First of all, thank you for your time

I have made this:

vanetza::asn1::Cpm cpm;

auto object = asn1::allocate<PerceivedObject_t>();
auto perception = asn1::allocate<PerceptionData_t>();
auto sensor = asn1::allocate<SensorInformation>();
auto free = asn1::allocate<FreeSpaceAddendum>();

PerceivedObject *arrayobjeto[2];

cpm->cpm.cpmParameters.perceptionData =

asn1::allocate();

cpm->header.protocolVersion = 2;
cpm->header.messageID = ItsPduHeader__messageID_cpm;
cpm->header.stationID = 1;
cpm->cpm.cpmParameters.managementContainer.stationType = 2;
cpmsolo->header.protocolVersion = 2;
cpmsolo->header.messageID = ItsPduHeader__messageID_cpm;
cpmsolo->header.stationID = 1;
cpmsolo->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();

ASSERT_TRUE(cpm.decode(buffer3));

It doesn't give me an error, but I have analyze and the encoder is not working properly because the decode is false. It seems the message is storing wrong, but I don't know what to change, woudl you kindly give me some advice?

Thank you very much

El mar, 18 oct 2022 a las 20:40, Raphael Riebl @.***>) escribió:

Hi @Santiago1969 https://github.com/Santiago1969,

if I remember corretly, you should pass perceptionData instead of perceptionData->list to ASN_SEQUENCE_ADD: EXPECT_EQ(0, ASN_SEQUENCE_ADD(cpm->cpm.cpmParameters.perceptionData, perception)); Unfortunately, the whole ASN.1 code is plain C, and thus the void* types accept any pointer type. One has to be extremely careful there and the compiler will just silently accept faulty code.

— Reply to this email directly, view it on GitHub https://github.com/riebl/vanetza/issues/168#issuecomment-1282850486, or unsubscribe https://github.com/notifications/unsubscribe-auth/AWMO7YOCJQ7HWICKZKE5ZG3WD3VH7ANCNFSM6AAAAAARCAMRSQ . You are receiving this because you were mentioned.Message ID: @.***>

Santiago1969 commented 1 year ago

Apparently I have the information stored in the payload correctly as it doesn't dissapear during the program, here you can see it:

imagen

There are no errors code, just the false result of the cpm.decode() function. Do you know if the structs _asn_ctx must be used for something? We have tried other software (OSS) and it fills the payload of the cpm with their own functions and it's interesting that they mark a special bit for these fields, PerceptionDataContainer and StationDataContainer. Maybe this mark is in _asn_ctx?

El mié, 19 oct 2022 a las 10:48, Santiago Lopez Coll (< @.***>) escribió:

Hi Raphael,

First of all, thank you for your time

I have made this:

vanetza::asn1::Cpm cpm;

auto object = asn1::allocate<PerceivedObject_t>();
auto perception = asn1::allocate<PerceptionData_t>();
auto sensor = asn1::allocate<SensorInformation>();
auto free = asn1::allocate<FreeSpaceAddendum>();

PerceivedObject *arrayobjeto[2];

cpm->cpm.cpmParameters.perceptionData =

asn1::allocate();

cpm->header.protocolVersion = 2;
cpm->header.messageID = ItsPduHeader__messageID_cpm;
cpm->header.stationID = 1;
cpm->cpm.cpmParameters.managementContainer.stationType = 2;
cpmsolo->header.protocolVersion = 2;
cpmsolo->header.messageID = ItsPduHeader__messageID_cpm;
cpmsolo->header.stationID = 1;
cpmsolo->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();

ASSERT_TRUE(cpm.decode(buffer3));

It doesn't give me an error, but I have analyze and the encoder is not working properly because the decode is false. It seems the message is storing wrong, but I don't know what to change, woudl you kindly give me some advice?

Thank you very much

El mar, 18 oct 2022 a las 20:40, Raphael Riebl @.***>) escribió:

Hi @Santiago1969 https://github.com/Santiago1969,

if I remember corretly, you should pass perceptionData instead of perceptionData->list to ASN_SEQUENCE_ADD: EXPECT_EQ(0, ASN_SEQUENCE_ADD(cpm->cpm.cpmParameters.perceptionData, perception)); Unfortunately, the whole ASN.1 code is plain C, and thus the void* types accept any pointer type. One has to be extremely careful there and the compiler will just silently accept faulty code.

— Reply to this email directly, view it on GitHub https://github.com/riebl/vanetza/issues/168#issuecomment-1282850486, or unsubscribe https://github.com/notifications/unsubscribe-auth/AWMO7YOCJQ7HWICKZKE5ZG3WD3VH7ANCNFSM6AAAAAARCAMRSQ . You are receiving this because you were mentioned.Message ID: @.***>