... | ... | @@ -298,6 +298,8 @@ So we need to have 2 callback functions: |
|
|
* First callback function `callback_encode_can_messages` will encode multiple (variable amount of) CAN messages
|
|
|
* Second callback function `callback_encode_can_bytes` will encode multiple data bytes of the CAN message.
|
|
|
|
|
|
### Encoding
|
|
|
|
|
|
We start by passing `N` number of CAN messages to `encode_packet` function. The `can_msg_count` variable passes the number of CAN messages in the `can_msg` array.
|
|
|
```
|
|
|
size_t encode_packet(proto_message *proto_pkt, serial_data_packet_s *packet, can_message_s *can_msg,
|
... | ... | @@ -383,8 +385,64 @@ static bool callback_encode_can_bytes(pb_ostream_t *ostream, const pb_field_t *f |
|
|
return is_success;
|
|
|
}
|
|
|
```
|
|
|
Thus subsequently all the CAN messages are encoded.
|
|
|
|
|
|
### Decoding
|
|
|
|
|
|
Now to decode the Array of CAN messages we reverse the encoding process. We pass an empty array of CAN message which will hold the decoded data from the `serial_data_packet_s *packet` data structure.
|
|
|
|
|
|
```
|
|
|
bool decode_packet(proto_message *proto_msg, serial_data_packet_s *packet, can_message_s *decoded_can_messages)
|
|
|
```
|
|
|
To decode the array of messages we register the callback `decode_callback_can_messages` to the `pb_callback_t` structure `can_msgs` and also pass the empty CAN message array to store the decoded CAN data. We then call Nanopb's `pb_decode()` API.
|
|
|
|
|
|
```
|
|
|
proto_msg->can_msgs.arg = (void *)decoded_can_messages;
|
|
|
proto_msg->can_msgs.funcs.decode = &decode_callback_can_messages;
|
|
|
|
|
|
/* Now we are ready to decode the message and Check for errors... */
|
|
|
if (!pb_decode(&stream, proto_message_fields, proto_msg)) {
|
|
|
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
|
|
|
return 0;
|
|
|
}
|
|
|
```
|
|
|
The `decode_callback_can_messages` callback is invoked for EACH repeated message. It again uses Nanopb's `pb_decode()` function to decode CAN message for a single message. It internally call the `callback_decode_can_bytes` callback as illustrated in the second example to encoded the 8 bytes of CAN message's data field.
|
|
|
|
|
|
```
|
|
|
static bool decode_callback_can_messages(pb_istream_t *istream, const pb_field_t *field, void **arg) {
|
|
|
bool is_success = true;
|
|
|
|
|
|
if ((NULL == arg) || (NULL == *arg)) {
|
|
|
is_success = false;
|
|
|
} else {
|
|
|
can_message_s *can_msgs_decoded = (can_message_s *)(*arg);
|
|
|
|
|
|
// Attempt to decode this proto message
|
|
|
proto_can_message proto_can_message = proto_can_message_init_zero;
|
|
|
|
|
|
// When the repeated data bytes are decoded, then invoke the callback: callback_decode_can_bytes
|
|
|
proto_can_message.data_byte.arg = (void *)can_msgs_decoded;
|
|
|
proto_can_message.data_byte.funcs.decode = callback_decode_can_bytes;
|
|
|
|
|
|
if (!pb_decode(istream, proto_can_message_fields, &proto_can_message)) {
|
|
|
is_success = false;
|
|
|
}
|
|
|
|
|
|
can_msgs_decoded->bus_id = proto_can_message.bus_id;
|
|
|
can_msgs_decoded->message_id = proto_can_message.message_id;
|
|
|
can_msgs_decoded->timestamp_ms = proto_can_message.timestamp_ms;
|
|
|
|
|
|
/* Next time the callback is invoked, the argument pointer will point to the next message
|
|
|
* Reference: 'protobuf.live_logs.arg = (void*) decoded_can_messages;' in the code below
|
|
|
*/
|
|
|
*arg += sizeof(can_message_s);
|
|
|
}
|
|
|
return is_success;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Thus subsequently all our CAN messages are encoded.
|
|
|
|
|
|
# External Resources
|
|
|
* [Protocol Buffer](https://developers.google.com/protocol-buffers/)
|
... | ... | |