# Functions of the Packet Dispatcher

## **Public API**

<span style="white-space: pre-wrap;">The following functions are available for the boards to use </span>**outside of**<span style="white-space: pre-wrap;"> the library.</span>

<span style="white-space: pre-wrap;">The public API consists of: </span>`<span class="editor-theme-code">packet_handler_t</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">packet_handler_config_t</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">PacketDispatcherInit(...)</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">DispatchPacket()</span>`  
<span style="white-space: pre-wrap;">There are also stack depth macros: </span>`<span class="editor-theme-code">PACKET_HANDLER_TASK_STACK_DEPTH_DEFAULT</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">PACKET_DISPATCHER_TASK_STACK_DEPTH</span>`

### 1) Stack depth macros

<p class="callout warning">**NOTE:** `<span class="editor-theme-code">PACKET_DISPATCHER_TASK_STACK_DEPTH</span>`<span style="white-space: pre-wrap;"> is currently defined but not actually used in the provided implementation!</span></p>

```none
#define PACKET_HANDLER_TASK_STACK_DEPTH_DEFAULT ((configSTACK_DEPTH_TYPE)512U)
#define PACKET_DISPATCHER_TASK_STACK_DEPTH ((configSTACK_DEPTH_TYPE)1024U)
```

---

### 2) packet\_handler\_t (callback)

```c
typedef result_t (*packet_handler_t)(void* buffer);
```

<span style="white-space: pre-wrap;">This type represents the </span>**callback function** <span style="white-space: pre-wrap;">invoked by a </span>**handler task**<span style="white-space: pre-wrap;"> when a packet of its type is received.</span>

#### Parameters

- `<span class="editor-theme-code">buffer</span>`

<span style="white-space: pre-wrap;">Pointer to the </span>**decoded packet payload** <span style="white-space: pre-wrap;">copied from the queue. The actual type of </span>`<span class="editor-theme-code">buffer</span>`<span style="white-space: pre-wrap;"> depends on the registered </span>`<span class="editor-theme-code">packet_type</span>`<span style="white-space: pre-wrap;"> in the config for the handler (see </span>[packet\_handler\_config\_t](#bkmrk-b.-packet_handler_co "b. packet_handler_config_t (struct)")).

<span style="white-space: pre-wrap;">For example, if a handler is registered for one specific protobuf payload type, the handler should cast </span>`<span class="editor-theme-code">buffer</span>`<span style="white-space: pre-wrap;"> to the corresponding generated struct type.</span>

<details id="bkmrk-examplestatic-result"><summary>Example</summary>

```c
static result_t Callback_ArmBoardControlSignals(void *buffer) {
    ArmBoardControlSignals* pckt = (ArmBoardControlSignals *)buffer;
    }
```

</details>##### Note on buffer typecasting

<p class="callout warning"><span style="white-space: pre-wrap;">The callback receives only a raw </span>`<span class="editor-theme-code">void *</span>`<span style="white-space: pre-wrap;">. That means type safety is </span>**entirely dependent on correct configuration!**</p>

- `<span class="editor-theme-code">packet_type</span>`<span style="white-space: pre-wrap;"> must match the actual protobuf payload member</span>
- `<span class="editor-theme-code">item_size</span>`<span style="white-space: pre-wrap;"> must match the size of that decoded payload type</span>
- <span style="white-space: pre-wrap;">handler must cast </span>`<span class="editor-theme-code">buffer</span>`<span style="white-space: pre-wrap;"> to the correct struct type</span>

If any of those mismatch, the code may compile while quietly doing something stupid (and it will be your fault :D).

#### Return value

<span style="white-space: pre-wrap;">Returns </span>`<span class="editor-theme-code">result_t</span>`<span style="white-space: pre-wrap;">. The handler task logs a warning if the return value is not </span>`<span class="editor-theme-code">RESULT_OK</span>`.

---

### 3) packet\_handler\_config\_t (struct)

<p class="callout info">**NOTE:**<span style="white-space: pre-wrap;"> there exist macros to make the configuration easier! </span>**See:**<span style="white-space: pre-wrap;"> </span>[Helper Macros for Static Handler Config](https://bookstack.roboteamtwente.nl/books/embedded-infastructure/page/helper-macros-for-handler-config "Helper Macros for Static Handler Config")</p>

```c
typedef struct {
    packet_handler_t handler;
    const char* task_name;
    pb_size_t packet_type;

    UBaseType_t task_priority;
    configSTACK_DEPTH_TYPE task_stack_depth;

    size_t item_size;
    UBaseType_t queue_length;

    uint8_t* queue_buffer;
    StaticQueue_t queue_struct;
    QueueHandle_t queue;
} packet_handler_config_t;
```

#### Purpose

<span style="white-space: pre-wrap;">Describes one packet type and the task/queue resources needed to process it. </span>**Each entry in the handler config array** <span style="white-space: pre-wrap;">(passed to </span>[PacketDispatcherInit(...)](#bkmrk-c.-packetdispatcheri "c. PacketDispatcherInit(...)")) **corresponds to one routed packet type!**

#### Fields

- `<span class="editor-theme-code">handler</span>`  
    <span style="white-space: pre-wrap;">Callback invoked when a packet of this type is received. Must not be </span>`<span class="editor-theme-code">NULL</span>`.
- `<span class="editor-theme-code">task_name</span>`  
    <span style="white-space: pre-wrap;">Name used when creating the FreeRTOS task. Must not be </span>`<span class="editor-theme-code">NULL</span>`.
- `<span class="editor-theme-code">packet_type</span>`  
    <span style="white-space: pre-wrap;">The protobuf discriminator value to match against </span>`<span class="editor-theme-code">DecodingEnvelopeCurrent.which_payload</span>`, which is the routing key.
- `<span class="editor-theme-code">task_priority</span>`  
    Priority of the FreeRTOS handler task. If set to zero, that is still a valid FreeRTOS priority value. There is no separate “unset” semantic here.
- `<span class="editor-theme-code">task_stack_depth</span>`  
    Stack depth for the handler task.  
    <span style="white-space: pre-wrap;">If </span>`<span class="editor-theme-code"><= 0</span>`<span style="white-space: pre-wrap;">, the implementation replaces it with: </span>`<span class="editor-theme-code">PACKET_HANDLER_TASK_STACK_DEPTH_DEFAULT</span>`<span style="white-space: pre-wrap;">. Since this type is typically unsigned, the </span>`<span class="editor-theme-code"><= 0</span>`<span style="white-space: pre-wrap;"> check effectively means “zero” in practice.</span>
- `<span class="editor-theme-code">item_size</span>`  
    <span style="white-space: pre-wrap;">Size of </span>**one** <span style="white-space: pre-wrap;">queued item. </span>

<p class="callout warning">This must match the size of the decoded payload type copied into the queue.</p>

- `<span class="editor-theme-code">queue_length</span>`  
    Number of items the queue can hold.
- `<span class="editor-theme-code">queue_buffer</span>`  
    Backing storage for static queue data.  
    <span style="white-space: pre-wrap;">Must be large enough for </span>`<span class="editor-theme-code">queue_length * item_size</span>`
- `<span class="editor-theme-code">queue_struct</span>`  
    <span style="white-space: pre-wrap;">Static queue control structure used internally by </span>`<span class="editor-theme-code">xQueueCreateStatic()</span>`. Caller provides storage but should not manually initialize runtime content.
- `<span class="editor-theme-code">queue</span>`  
    Queue handle written internally during initialization.

<p class="callout danger">Caller should not pre-fill it!</p>

---

### 4) PacketDispatcherInit(...)

```c
result_t PacketDispatcherInit(packet_handler_config_t* handlers,
                              size_t handler_count);
```

**Initializes the dispatcher**<span style="white-space: pre-wrap;"> by...</span>

- storing the handler registry
- <span style="white-space: pre-wrap;">creating </span>**one queue**<span style="white-space: pre-wrap;"> and </span>**one task**<span style="white-space: pre-wrap;"> per handler entry</span>

#### Parameters

- `<span class="editor-theme-code">handlers</span>`  
    <span style="white-space: pre-wrap;">Pointer to an array of handler configurations (see above: </span>[packet\_handler\_config\_t](https://bookstack.roboteamtwente.nl/books/embedded-infastructure/page/packet-dispatcher#bkmrk-b.-packet_handler_co "b. (struct) packet_handler_config_t")). The implementation stores a global pointer to it and passes individual entries to tasks.
- `<span class="editor-theme-code">handler_count</span>`  
    Number of entries in the array.

<p class="callout danger">**IMPORTANT:**<span style="white-space: pre-wrap;"> The </span>`<span class="editor-theme-code">handlers</span>`<span style="white-space: pre-wrap;"> array </span>**must remain valid for the full lifetime**<span style="white-space: pre-wrap;"> of the system. Do </span>**NOT** allocate this array on a temporary stack frame unless you are into being abused by segfaults :)</p>

---

### 5) DispatchPacket(...)

```c
void DispatchPacket(receive_frame* incoming_packet);
```

**Decodes**<span style="white-space: pre-wrap;"> one incoming raw frame and </span>**routes** its decoded payload to the appropriate handler queue.

##### Internal functioning

1. validates basic frame properties
2. creates a nanopb input stream from the raw bytes
3. <span style="white-space: pre-wrap;">decodes into the global static </span>`<span class="editor-theme-code">DecodingEnvelopeCurrent</span>`
4. scans the registered handler list
5. <span style="white-space: pre-wrap;">finds the first handler whose </span>`<span class="editor-theme-code">packet_type</span>`<span style="white-space: pre-wrap;"> matches </span>`<span class="editor-theme-code">which_payload</span>`
6. <span style="white-space: pre-wrap;">sends </span>`<span class="editor-theme-code">DecodingEnvelopeCurrent.payload</span>`<span style="white-space: pre-wrap;"> to that handler’s queue</span>
7. returns

If no matching handler is found, it logs a warning. If decode fails, it logs an error.

<p class="callout danger">**NOTE:**<span style="white-space: pre-wrap;"> This function returns </span>`<span class="editor-theme-code">void</span>`, so dispatch failure is **only observable through logs**.</p>

#### Parameters

- `<span class="editor-theme-code">incoming_packet</span>`  
    <span style="white-space: pre-wrap;">Pointer to a transport frame containing </span>`<span class="editor-theme-code">payload</span>`<span style="white-space: pre-wrap;">, </span>`<span class="editor-theme-code">len</span>`<span style="white-space: pre-wrap;"> of the incoming packet.</span>

---

## **Internal (private) task model**

### `<span class="editor-theme-code">PacketHandlerTask()</span>`

<p class="callout info"><span style="white-space: pre-wrap;">Also see </span>[note on handler task lifecycles](https://bookstack.roboteamtwente.nl/link/228#bkmrk-note-on-handler-task)<span style="white-space: pre-wrap;"> !</span></p>

Each handler config gets its own task (and corresponding queue, remember ladies?) running this loop:

1. validate config and resources
2. <span style="white-space: pre-wrap;">allocate one packet buffer using </span>`<span class="editor-theme-code">malloc(conf->item_size)</span>`
3. <span style="white-space: pre-wrap;">block forever on </span>`<span class="editor-theme-code">xQueueReceive()</span>`
4. when a packet arrives:
    - <span style="white-space: pre-wrap;">call </span>`<span class="editor-theme-code">conf->handler(packet_buffer)</span>`
    - log if handler returns error

#### Purpose of per-task buffer

<span style="white-space: pre-wrap;">The queue copies incoming items into the task’s local </span>`<span class="editor-theme-code">packet_buffer</span>`<span style="white-space: pre-wrap;">. That means the handler callback receives a stable task-local buffer for the duration of the callback. The callback does </span>**not**<span style="white-space: pre-wrap;"> receive a pointer directly into the global decode object.</span>

<p class="callout warning"><span style="white-space: pre-wrap;">The task allocates its buffer dynamically with </span>`<span class="editor-theme-code">malloc()</span>`<span style="white-space: pre-wrap;"> once at startup and never frees it, because the task is intended to live forever.</span></p>

---

## **Macros**

<p class="callout info"><span style="white-space: pre-wrap;">There exist macros to make the configuration of a handler easier! See: </span>[Helper Macros for Static Handler Config](https://bookstack.roboteamtwente.nl/books/embedded-infastructure/page/helper-macros-for-handler-config "Helper Macros for Static Handler Config").</p>

##   