Skip to main content

Recommended Usage Pattern

More information on the mentioned steps can be found in Functions of the Packet Dispatcher



Typical Usage Model

Intended setup

  1. Define one handler function per packet type
  2. define one packet_handler_config_t entry per packet type (using the macros)
  3. provide queue storage buffers
    (When using the macros, you do not need to do this manually)
  4. call PacketDispatcherInit(...)
  5. whenever a frame arrives, call DispatchPacket()

Flow after setup

  1. Ethernet/UDP receives raw frame
  2. networking code builds receive_frame
  3. DispatchPacket() decodes it
  4. payload type is matched
  5. decoded payload is copied into target queue
  6. matching handler task wakes
  7. the callback processes typed payload


Examples

1) Using macros

//Imports
#include "packet_dispatcher.h"
#include "packet_dispatcher_macros.h"

/*Define handler callbacks*/
static result_t handle_drive_msg(void* buffer) {
    PBDriveMsg* msg = (PBDriveMsg*)buffer;
    return process_drive_msg(msg);
}

static result_t handle_sensor_diag(void* buffer) {
    PBSensorDiag* msg = (PBSensorDiag*)buffer;
    return process_sensor_diag(msg);
}

PACKET_HANDLER_CONFIG_STATIC(drive_handler_cfg,
                             PBEnvelope_drive_msg_tag,
                             drive_msg,
                             handle_drive_msg);

PACKET_HANDLER_CONFIG_STATIC_QUEUE(sensor_diag_handler_cfg,
                                   PBEnvelope_sensor_diag_tag,
                                   sensor_diag,
                                   handle_sensor_diag,
                                   10U);

static packet_handler_config_t* handlers[] = {
    drive_handler_cfg,
    sensor_diag_handler_cfg,
};


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.