# Recommended Usage Pattern

<p class="callout info"><span style="white-space: pre-wrap;">More information on the mentioned steps can be found in </span>[Functions of the Packet Dispatcher](https://bookstack.roboteamtwente.nl/books/embedded-infastructure/page/functions-of-the-packet-dispatcher "Functions of the Packet Dispatcher")</p>

---

## **Typical Usage Model**

### Intended setup

1. <span style="white-space: pre-wrap;">Define one </span>[handler function](https://bookstack.roboteamtwente.nl/link/229#bkmrk-2%29-packet_handler_t-)<span style="white-space: pre-wrap;"> per packet type</span>
2. <span style="white-space: pre-wrap;">define one </span>[packet\_handler\_config\_t](https://bookstack.roboteamtwente.nl/link/229#bkmrk-2%29-packet_handler_co)<span style="white-space: pre-wrap;"> entry per packet type (using the </span>[macros](https://bookstack.roboteamtwente.nl/books/embedded-infastructure/page/helper-macros-for-handler-config "Helper Macros for Handler Config"))
3. provide queue storage buffers  
    <span style="white-space: pre-wrap;">(When using the </span>[macros](https://bookstack.roboteamtwente.nl/books/embedded-infastructure/page/helper-macros-for-handler-config), you do not need to do this manually)
4. <span style="white-space: pre-wrap;">call </span>[PacketDispatcherInit(...)](https://bookstack.roboteamtwente.nl/link/229#bkmrk-4%29-packetdispatcheri)
5. <span style="white-space: pre-wrap;">whenever a frame arrives, call </span>[DispatchPacket()](https://bookstack.roboteamtwente.nl/link/229#bkmrk-5%29-dispatchpacket%28..)

### Flow after setup

1. Ethernet/UDP receives raw frame
2. <span style="white-space: pre-wrap;">networking code builds </span>`<span class="editor-theme-code">receive_frame</span>`
3. `<span class="editor-theme-code">DispatchPacket()</span>`<span style="white-space: pre-wrap;"> decodes it</span>
4. payload type is matched
5. decoded payload is copied into target queue
6. matching handler task wakes
7. the callback processes typed payload

---

## **IMPORTANT configuration rules**

<p class="callout danger">This module is heavily configuration-driven. Several things must match exactly.</p>

#### <span style="white-space: pre-wrap;">I. </span>`<span class="editor-theme-code">packet_type</span>`<span style="white-space: pre-wrap;"> must match the protobuf discriminator</span>

<span style="white-space: pre-wrap;">Each handler’s </span>`<span class="editor-theme-code">packet_type</span>`<span style="white-space: pre-wrap;"> must be the exact value used by </span>`<span class="editor-theme-code">PBEnvelope.which_payload</span>`. If this is wrong, packets will never reach that handler.

#### <span style="white-space: pre-wrap;">II. </span>`<span class="editor-theme-code">item_size</span>`<span style="white-space: pre-wrap;"> must match the decoded payload type</span>

<span style="white-space: pre-wrap;">The queue copies bytes from </span>`<span class="editor-theme-code">&DecodingEnvelopeCurrent.payload</span>`<span style="white-space: pre-wrap;"> into a queue item of size </span>`<span class="editor-theme-code">item_size</span>`.

<span style="white-space: pre-wrap;">If </span>`<span class="editor-theme-code">item_size</span>`<span style="white-space: pre-wrap;"> is:</span>

- too small -&gt; payload will be truncated
- too large -&gt; copied data may include unrelated union bytes or layout assumptions
- wrong type entirely -&gt; handler sees garbage with confidence

#### <span style="white-space: pre-wrap;">III. </span>`<span class="editor-theme-code">queue_buffer</span>`<span style="white-space: pre-wrap;"> must be sized correctly</span>

<span style="white-space: pre-wrap;">The backing storage must be at least: </span>`<span class="editor-theme-code">queue_length * item_size</span>`<span style="white-space: pre-wrap;">. </span>**If not, queue creation or runtime behavior is invalid.**

#### <span style="white-space: pre-wrap;">IV. Handler must cast </span>`<span class="editor-theme-code">void *</span>`<span style="white-space: pre-wrap;"> correctly</span>

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

<span style="white-space: pre-wrap;">The current </span>`<span class="editor-theme-code">PacketDispatcherInit()</span>`<span style="white-space: pre-wrap;"> API expects:</span>

```c
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:

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

NOT an array of pointers.

---

## **Examples**

### 1) Using macros

```c
//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

```c
//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:

```c
result_t res = PacketDispatcherInit(handlers, ARRAY_LEN(handlers));
```

And during frame reception:

```c
DispatchPacket(&rx_frame);
```

####   