Recommended Usage Pattern
More information on the mentioned steps can be found in Functions of the Packet Dispatcher
Typical Usage Model
Intended setup
- Define one handler function per packet type
- define one packet_handler_config_t entry per packet type (using the macros)
- provide queue storage buffers
(When using the macros, you do not need to do this manually) - call PacketDispatcherInit(...)
- whenever a frame arrives, call DispatchPacket()
Flow after setup
- Ethernet/UDP receives raw frame
- networking code builds
receive_frame DispatchPacket()decodes it- payload type is matched
- decoded payload is copied into target queue
- matching handler task wakes
- the callback processes typed payload
IMPORTANT configuration rules
This module is heavily configuration-driven. Several things must match exactly.
I. packet_type must match the protobuf discriminator
Each handler’s packet_type must be the exact value used by PBEnvelope.which_payload. If this is wrong, packets will never reach that handler.
II. item_size must match the decoded payload type
The queue copies bytes from &DecodingEnvelopeCurrent.payload into a queue item of size item_size.
If item_size is:
- too small -> payload will be truncated
- too large -> copied data may include unrelated union bytes or layout assumptions
- wrong type entirely -> handler sees garbage with confidence
III. queue_buffer must be sized correctly
The backing storage must be at least: queue_length * item_size. If not, queue creation or runtime behavior is invalid.
IV. Handler must cast void * correctly
The callback receives a raw buffer pointer. It must cast to the correct generated protobuf type.
V. Handlers array must be an array of structs
The current PacketDispatcherInit() API expects:
packet_handler_config_t* handlers
meaning a contiguous array of structs, not an array of pointers.
So with the current implementation, the final array should actually be:
static packet_handler_config_t* handlers[] = {
drive_handler_cfg,
sensor_diag_handler_cfg,
};
NOT an array of pointers.
Examples
1) Using macros
//Imports
#include "packet_dispatcher.h"
#include "packet_dispatcher_macros.h"
/*Define handler callbacks*/
//Callback for protobuf of type ArmBoardMovementFeedback
static result_t Callback_ArmBoardMovementFeedback(void *buffer) {
if (buffer == NULL) {
return RESULT_ERR_INVALID_ARG;
}
ArmBoardMovementFeedback* pckt = (ArmBoardMovementFeedback *)buffer; //Retreive the packet
pckt->arm_error; //Get fields of protobuf
//Do something...
return RESULT_OK;
}
//Config using most basic macro
PACKET_HANDLER_CONFIG_STATIC(Handler_ArmBoardMovementFeedback, PBEnvelope_arm_feedback_tag, arm_feedback, Callback_ArmBoardMovementFeedback);
//Callback for protobuf of type ArmBoardControlSignals
static result_t Callback_ArmBoardControlSignals(void *buffer) {
if (buffer == NULL) {
return RESULT_ERR_INVALID_ARG;
}
ArmBoardControlSignals* pckt = (ArmBoardControlSignals *)buffer;
pckt->control_base; //Get fields of protobuf
pckt->control_gripper_pitch;
//... etc etc
//Do something...
return RESULT_OK;
}
//Config using most basic macro
PACKET_HANDLER_CONFIG_STATIC(Handler_ArmBoardControlSignals, PBEnvelope_arm_ctrl_tag, arm_ctrl, Callback_ArmBoardControlSignals);
//Add configs to the list of configs
static packet_handler_config_t* handlers[] = {Handler_ArmBoardMovementFeedback, Handler_ArmBoardControlSignals};
//HERE WE PUT ETH_init(...) and the creation of queues from the networking board
//See respective documentation
PacketDispatcherInit(handlers, 2);
ETH_udp_init(2, queues, DispatchPacket); //Passing DispatchPacket to ETH_udp_init makes sure it gets called upon receiving msgs
//Once again, after this we can use networking and do ETH_add_arp(...) and ETH_udp_send(...)
2) Manual configuration
//Imports
#include "packet_dispatcher.h"
static result_t handle_drive_cmd(void* buffer) {
PBDriveCommand* msg = (PBDriveCommand*)buffer;
return drive_process(msg);
}
static result_t handle_arm_cmd(void* buffer) {
PBArmCommand* msg = (PBArmCommand*)buffer;
return arm_process(msg);
}
static uint8_t drive_queue_storage[8 * sizeof(PBDriveCommand)];
static uint8_t arm_queue_storage[4 * sizeof(PBArmCommand)];
static packet_handler_config_t handlers[] = {
{
.handler = handle_drive_cmd,
.task_name = "drive_pkt",
.packet_type = PBEnvelope_drive_cmd_tag,
.task_priority = 3,
.task_stack_depth = 512,
.item_size = sizeof(PBDriveCommand),
.queue_length = 8,
.queue_buffer = drive_queue_storage,
},
{
.handler = handle_arm_cmd,
.task_name = "arm_pkt",
.packet_type = PBEnvelope_arm_cmd_tag,
.task_priority = 3,
.task_stack_depth = 512,
.item_size = sizeof(PBArmCommand),
.queue_length = 4,
.queue_buffer = arm_queue_storage,
},
};
Then during startup:
result_t res = PacketDispatcherInit(handlers, ARRAY_LEN(handlers));
And during frame reception:
DispatchPacket(&rx_frame);