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
Examples
1) Using macros
//Imports
#include "packet_dispatcher.h"
#include "packet_dispatcher_macros.h"
/*Define handler callbacks*/
static//Callback result_tfor handle_drive_msg(void*protobuf buffer)of {type PBDriveMsg* msg = (PBDriveMsg*)buffer;
return process_drive_msg(msg);
}ArmBoardMovementFeedback
static result_t handle_sensor_diag(void*Callback_ArmBoardMovementFeedback(void *buffer) {
PBSensorDiag*if msg(buffer == NULL) {
return RESULT_ERR_INVALID_ARG;
}
ArmBoardMovementFeedback* pckt = (PBSensorDiag*ArmBoardMovementFeedback *)buffer; //Retreive the packet
pckt->arm_error; //Get fields of protobuf
//Do something...
return process_sensor_diag(msg);RESULT_OK;
}
//Config using most basic macro
PACKET_HANDLER_CONFIG_STATIC(drive_handler_cfg,Handler_ArmBoardMovementFeedback, PBEnvelope_drive_msg_tag,PBEnvelope_arm_feedback_tag, drive_msg,arm_feedback, handle_drive_msg)Callback_ArmBoardMovementFeedback);
PACKET_HANDLER_CONFIG_STATIC_QUEUE(sensor_diag_handler_cfg,//Callback PBEnvelope_sensor_diag_tag,for sensor_diag,protobuf handle_sensor_diag,of 10U)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, drive_handler_cfg,
sensor_diag_handler_cfg,
}Handler_ArmBoardControlSignals};
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);
Important note about array type
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.
That distinction matters. The macros define actual config objects, not pointers.
c. 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.