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?
Hello nano developers,
I'd like to realize the following proto:
message container {
enum MessageType {
TYPE_UNKNOWN = 0;
evt_resultStatus = 1;
}
required MessageType mt = 1;
optional bytes cmd_evt_transfer = 2;
}
message evt_resultStatus {
required int32 operationMode = 1;
}
...
The dots denote, there are more messages with (multiple) primitive containing datatypes to come. The enum will grow likewise, just wanted to keep it short.
The container gets generated as:
typedef struct _container {
container_MessageType mt;
pb_callback_t cmd_evt_transfer;
} container;
evt_resultStatus is:
typedef struct _evt_resultStatus {
int32_t operationMode;
} evt_resultStatus;
The field cmd_evt_transfer should act as a proxy of subsequent messages like evt_resultStatus holding primitive datatypes.
evt_resultStatus shall be encoded into bytes and be placed into the cmd_evt_transfer field.
Then the container shall get encoded and the encoding result will be used for subsequent transfers.
The background why to do so, is to shorten the proto definition and avoid the oneof thing. Unfortunately syntax version 3 is not fully supported, so we can not make use of any fields.
The first question is: will this approach be possible?
What I've got so far is the encoding including the callback which seems to behave fine. But on the other side, decoding somehow skips the callback. I've read issues here, that this happened also when using oneof and bytes fields.
Can someone please clarify on how to proceed with this?
Sample code so far I got:
bool encode_msg_test(pb_byte_t* buffer, int32_t sval, size_t* sz, char* err) {
evt_resultStatus rs = evt_resultStatus_init_zero;
rs.operationMode = sval;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/*encode container*/
container msg = container_init_zero;
msg.mt = container_MessageType_evt_resultStatus;
msg.cmd_evt_transfer.arg = &rs;
msg.cmd_evt_transfer.funcs.encode = encode_cb;
if(! pb_encode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sz = stream.bytes_written;
return true;
}
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
//with the below in place a stream full error rises
// if (! pb_encode_tag_for_field(stream, field)) {
// return false;
// }
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
//buffer holds previously encoded data
bool decode_msg_test(pb_byte_t* buffer, int32_t* sval, size_t msg_len, char* err) {
container msg = container_init_zero;
evt_resultStatus res = evt_resultStatus_init_zero;
msg.cmd_evt_transfer.arg = &res;
msg.cmd_evt_transfer.funcs.decode = decode_cb;
pb_istream_t stream = pb_istream_from_buffer(buffer, msg_len);
if(! pb_decode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sval = res.operationMode;
return true;
}
bool decode_cb(pb_istream_t *istream, const pb_field_t *field, void **arg) {
evt_resultStatus * rs = (evt_resultStatus*)(*arg);
if(! pb_decode(istream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
I feel, I don't have a proper understanding of the encoding / decoding process.
Is it correct to assume:
the first call of pb_encode (in encode_msg_test) takes care of the mt field
the second call of pb_encode (in encode_cb) handles the cmd_evt_transfer field
If I do:
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
if (! pb_encode_tag_for_field(stream, field)) {
return false;
}
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
then I get a stream full error on the call of pb_encode.
Why is that?
Yes, the approach is reasonable. Nanopb callbacks do not care what the actual data read or written by the callback is.
As for why your decode callback is not working, you'll need to post the code you are using for decoding.
(As an aside, Any type does work in nanopb and is covered by this test case. But the type_url included in all Any messages makes them have a quite large overhead.)
I have the following typedefined struct:
typedef struct
{
uint8_t u8Byte1; // This byte takes the needed values sometimes
uint8_t u8Byte2; // Not used
uint8_t u8Byte3; // This byte takes the needed values the other times
uint8_t u8Byte4; // Not used
} tstrMapMetadata;
And I have a thread that fills (with data from a sensor) this struct and uses one of its values:
while(true)
{
tstrMapMetadata * pstrMapMetadata = something();
if(pstrMapMetadata->u8Byte1 == SOMETHING) //<---- this line
{
//Do something special
}
}
But now I have a condition (constant during the thread) in which I want the comparison of the marked line done with u8Byte3 instead of u8Byte1.
Of course I could
if(((condition) ? pstrMapMetadata->u8Byte1 : pstrMapMetadata->u8Byte3) == SOMETHING) //<---- this line
But the I would be doing the same comparison all the time.
Is there a way to point to one of the members (are they called like this?) of the struct before its declaration?
Something like (this code of course doesn't work but gives an idea of what I'm looking for):
uint8_t * coolPointer;
if(condition)
{
coolPointer = (someOperation)tstrMapMetadata(u8Byte1);
}
else
{
coolPointer = (someOperation)tstrMapMetadata(u8Byte3);
}
while(true)
{
tstrMapMetadata * pstrMapMetadata = something();
if(coolPointer == SOMETHING) //<---- this line
{
//Do something special
}
}
Thanks!
There is pointer to member:
uint8_t tstrMapMetadata::*member = condition ?
&tstrMapMetadata::u8Byte1 :
&tstrMapMetadata::u8Byte3;
while (true)
{
tstrMapMetadata* pstrMapMetadata = something();
if (pstrMapMetadata->*member == SOMETHING) // usage with ->* ( .* for objet )
{
//Do something special
}
}
this is my first post here!
I'm working on a code that parses Json to fill a struct that I append to a Qlist of tests to run.
My problem is with the payload inside my struct: when I send the first object in my list the payload it is not empty when it should be.
struct FrameTest {
QString protocol;
QString Length;
QByteArray *payload;
};
QList<FrameTest> _validTestLists;
FrameTest TxFrame;
Code of the JSON parser
void Cesa::JsonParser(QJsonObject _ScriptTestObject)
{
TxFrame.protocol = "00";
TxFrame.Length = "00";
TxFrame.payload = new QByteArray();
for(QJsonObject::iterator it = _ScriptTestObject.begin(); it!=_ScriptTestObject.end(); ++it)
{
TxFrame.protocol= "00";
TxFrame.Length = "00";
TxFrame.payload->clear();
_CmdObject = _ScriptTestObject.value(key).toObject(); // Get Json object
if (_CmdObject.contains("Board") && _CmdObject.value("Board") == "Exia")
{
QString payload;
TxFrame.protocol= "03";
TxFrame.Length = "06";
payload = QString("%1").arg(obj.value("hopPeriod").toInt(), 2, 16, QChar('0'));
}
else if (_CmdObject.contains("Board") && _CmdObject.value("Board") == "Cevee")
{
TxFrame.protocol= "03";
TxFrame.Length = "06";
}
_testLists.append(TxFrame);
}
Test(_testLists); // Test with only one object
Function for sending via port COM
bool Cesa::Test(FrameTest frame)
{
QByteArray txFrame;
/* Transmit command */
txFrame.insert(0, frame.protocol);
txFrame.insert(2, frame.Length);
txFrame.insert(4, *frame.payload);
_comPort->write(QByteArray::fromHex(txFrame));
}
I'm a student still learning coding, any help and advice will be appreciated :)
Given this schema
struct TestObject
{
value1 #0 : Int32 = -5;
value2 #1 : Float32 = 9.4;
}
struct TestContainer
{
object #0: TestObject;
}
Is it possible to get an AnyPointer::Builder from the TestObject::Builder in c++ code?
This is what I am trying to do:
::capnp::MallocMessageBuilder message;
auto container = message.initRoot<TestContainer>();
TestObject::Builder objBuilder = container.initObject();
//Get an AnyPointer
capnp::AnyPointer::Builder anyBuilder = capnp::toAny( objBuilder )(); //No this does not work.
MyTestObject test( 41, 643.7f );
test.serialise( anyBuilder );
What I am trying to do is have an abstract interface with a single argument type
eg.
class ISerialisable
{
virtual void serialise(capnp::AnyPointer::Builder& any) = 0;
}
class MyTestObject: public ISerialisable
{
void serialise(capnp::AnyPointer::Builder& any) override
{
auto testObjBuilder = any.getAs<TestObject>(); or should initAs be used?
testObject.setValue1( whatever1);
testObject.setValue2( whatever2);
}
}
Is it possible to go down this route?