# Helper Macros for Handler Config

## **Purpose**

<span style="white-space: pre-wrap;">To reduce repetitive boilerplate when defining packet handlers, the module also provides a set of helper macros in </span>`<span class="editor-theme-code">packet_dispatcher_macros.h</span>`.

These macros generate:

- a statically allocated queue buffer
- <span style="white-space: pre-wrap;">a fully initialized </span>`<span class="editor-theme-code">packet_handler_config_t</span>`

<p class="callout info"><span style="white-space: pre-wrap;">They are especially useful because they automatically derive the correct queue item size from the selected </span>`<span class="editor-theme-code">PBEnvelope</span>`<span style="white-space: pre-wrap;"> payload member, which helps avoid one of the easiest mistakes in this module: mismatching </span>`<span class="editor-theme-code">item_size</span>`<span style="white-space: pre-wrap;"> with the actual decoded protobuf payload type.</span></p>

### Why these macros are useful

Without these macros, every handler config has to manually specify:

- queue storage buffer
- queue length
- item size
- task name
- default priority
- default stack depth
- queue initialization fields

That is tedious and error-prone.

#### <span style="white-space: pre-wrap;">I) They derive </span>`<span class="editor-theme-code">item_size</span>`<span style="white-space: pre-wrap;"> automatically</span>

<span style="white-space: pre-wrap;">Each macro uses: </span>`<span class="editor-theme-code">sizeof(((PBEnvelope*)0)->payload.payload_member)</span>`<span style="white-space: pre-wrap;"> to compute the exact size of the selected envelope payload member at compile time. This removes the need to manually write </span>`<span class="editor-theme-code">.item_size = sizeof(MyPayloadType)</span>`<span style="white-space: pre-wrap;"> and reduces the chance of queue item size mismatches.</span>

#### II) They allocate queue storage automatically

Each macro also declares:

```c
static uint8_t name##_queue_buffer[...];
```

with the correct total size based on:

- payload member size
- selected queue length

So the queue backing storage is generated alongside the config object.

### Important consequence of these macros

<p class="callout info"><span style="white-space: pre-wrap;">These macros define </span>**static objects**.</p>

That means each use creates:

- a static queue buffer
- <span style="white-space: pre-wrap;">a static </span>`<span class="editor-theme-code">packet_handler_config_t</span>`

<p class="callout info">This is generally what you want for a dispatcher configuration that should live for the full lifetime of the system.</p>

It also means:

- they should normally be used at file scope
- <span style="white-space: pre-wrap;">using the same </span>`<span class="editor-theme-code">name</span>`<span style="white-space: pre-wrap;"> twice in one translation unit will cause symbol redefinition</span>
- they are not runtime factory macros, they are compile-time object definition helpers

---

## **Shared Functionality**

<span style="white-space: pre-wrap;">For </span>**all** of these macros, the generated config uses:

```c
#define PACKET_HANDLER_CONFIG_STATIC(name, packet_tag, payload_member_size, handler_fn)

.handler = (handler_fn)
.task_name = #name
.packet_type = (packet_tag)
.item_size = payload_member_size
.queue_buffer = name##_queue_buffer
.queue_struct = {0}
.queue = NULL
```

This is helpful for two reasons:

- `<span class="editor-theme-code">task_name</span>`<span style="white-space: pre-wrap;"> is automatic</span>  
    The task name becomes **the same as the symbol (handler config itself) name**, which keeps config definitions compact and readable.
- Queue internals are initialized consistently  
    <span style="white-space: pre-wrap;">The queue control structure is zero-initialized, and the runtime queue handle starts as </span>`<span class="editor-theme-code">NULL</span>`, matching the expectations of the dispatcher startup code.

### <span style="white-space: pre-wrap;">IMPORTANT NOTE on </span>`<span class="editor-theme-code">payload_member</span>`

<p class="callout info"><span style="white-space: pre-wrap;">The </span>`<span class="editor-theme-code">payload_member</span>`<span style="white-space: pre-wrap;"> argument is not the packet type name. It is the </span>**member name inside** `<span class="editor-theme-code">PBEnvelope.payload</span>`**!**</p>

<span style="white-space: pre-wrap;">This matters because the macros compute size using direct member access syntax: </span>`<span class="editor-theme-code">sizeof( ((PBEnvelope*)0) -> payload.payload_member)</span>`<span style="white-space: pre-wrap;">. </span>**So, if the wrong member name is used, compilation will fail, which is actually helpful for once.**

**The member names are defined in** `<span class="editor-theme-code">envelope.pb.h</span>`<span style="white-space: pre-wrap;"> </span>**.**  
<span style="white-space: pre-wrap;">For example, currently </span>`<span class="editor-theme-code">envelope.pb.h</span>`<span style="white-space: pre-wrap;"> contains the following:</span>

```c
typedef struct _PBEnvelope {
    pb_size_t which_payload;
  
    union _PBEnvelope_payload {
            /* Sensorboard messages */
            SensorBoardPHInfo ph_info;
            
            /* Armboard messages */
            ArmBoardControlSignals arm_ctrl;
            ArmBoardDiagnostics arm_diag;
    
            //etc etc...
    }
}
```

<p class="callout success"><span style="white-space: pre-wrap;">So, the macro must be called with the member name </span>**matching the rest of the config**<span style="white-space: pre-wrap;">, such as </span>`<span class="editor-theme-code">ph_info</span>`<span style="white-space: pre-wrap;"> or </span>`<span class="editor-theme-code">arm_ctrl</span>`<span style="white-space: pre-wrap;"> and </span>**NOT** the protobuf struct type name!</p>

---

## **Available macros**

### 1) Default configuration macros

The header defines these default values:

```none
#define PACKET_HANDLER_DEFAULT_PRIORITY (tskIDLE_PRIORITY + 2U)
#define PACKET_HANDLER_DEFAULT_QUEUE_LENGTH (5U)
#define PACKET_HANDLER_DEFAULT_STACK_DEPTH (0U)
```

- `<span class="editor-theme-code">PACKET_HANDLER_DEFAULT_PRIORITY</span>`  
    Default FreeRTOS task priority assigned to handler tasks created with the simpler macros.
- `<span class="editor-theme-code">PACKET_HANDLER_DEFAULT_QUEUE_LENGTH</span>`  
    Default number of queued packets per handler.
- `<span class="editor-theme-code">PACKET_HANDLER_DEFAULT_STACK_DEPTH</span>`  
    Default stack depth field stored in the config.  
    <span style="white-space: pre-wrap;">A value of </span>`<span class="editor-theme-code">0U</span>`<span style="white-space: pre-wrap;"> is intentional here. In the dispatcher implementation, a task stack depth of zero is treated as “use the dispatcher default,” which becomes: </span>`<span class="editor-theme-code">PACKET_HANDLER_TASK_STACK_DEPTH_DEFAULT</span>`<span style="white-space: pre-wrap;">. So this macro does </span>**not**<span style="white-space: pre-wrap;"> mean “zero stack.” It means “defer to the runtime default chosen by the dispatcher.”</span>

---

### <span style="white-space: pre-wrap;">2) Basic config: </span>`<span class="editor-theme-code">PACKET_HANDLER_CONFIG_STATIC</span>`

```
#define PACKET_HANDLER_CONFIG_STATIC(name, packet_tag, payload_member_size, handler_fn)
```

This is the simplest form. Creates a handler config using:

- **default** priority
- **default** queue length
- **default** stack depth behaviour

##### Parameters

- `<span class="editor-theme-code">name</span>`  
    User defined name, go crazy.
- `<span class="editor-theme-code">packet_tag</span>`  
    <span style="white-space: pre-wrap;">This is the Nanopb generated tag for the packet type. They follow the pattern </span>`<span class="editor-theme-code">PBEnvelope_[</span>`*`<em class="editor-theme-code editor-theme-italic">payload_member</em>`*`<span class="editor-theme-code">]_tag</span>`. So for example: PBEnvelope\_arm\_ctrl\_tag
- `<span class="editor-theme-code">payload_member</span>`  
    <span style="white-space: pre-wrap;">See </span>[important note on payload\_member](#header-3a64 "IMPORTANT NOTE on payload_member")<span style="white-space: pre-wrap;">. </span>**Needs to match the packet\_tag and the buffer type the callback is specified for!**
- `<span class="editor-theme-code">handler_fn</span>`  
    <span style="white-space: pre-wrap;">Callback function. Type signature </span>[packet\_handler\_t](https://bookstack.roboteamtwente.nl/books/embedded-infastructure/page/functions-of-the-packet-dispatcher#bkmrk-a.-packet_handler_t- "Functions of the packet dispatcher").

#####   


##### Example

```c
/* Config for: ArmBoardMovementFeedback */

//Define the callback function with the specified signature
static result_t Callback_ArmBoardMovementFeedback(void *buffer) {
  if (buffer == NULL) {
    return RESULT_ERR_INVALID_ARG;
  }

  //Retreive the packet
  ArmBoardMovementFeedback* pckt = (ArmBoardMovementFeedback *)buffer;
  //Get all fields
  pckt->arm_error; 

  /*
  Go wild...
  */
  return RESULT_OK;
}

PACKET_HANDLER_CONFIG_STATIC(
  Handler_ArmBoardMovementFeedback,   // NOTE: This name is USER DEFINED, let your imagination run
  PBEnvelope_arm_feedback_tag,        //  Make sure these...
  arm_feedback,                       //                   ... MATCH!
  Callback_ArmBoardMovementFeedback); // Callback as above
```

---

### <span style="white-space: pre-wrap;">3) Full config: </span>`<span class="editor-theme-code">PACKET_HANDLER_CONFIG_STATIC_EX</span>`

```none
#define PACKET_HANDLER_CONFIG_STATIC_EX(name, packet_tag, payload_member, handler_fn, 
                                        priority_, stack_depth_, queue_length_)
```

Full explicit version. Lets you set:

- name, packet\_tag, payload\_member, handler\_fn as above
- **custom** priority
- **custom** stack depth
- **custom** queue length

##### Best used when

- the handler needs a non-default stack size
- you want fully explicit resource configuration

##### Example

```c
PACKET_HANDLER_CONFIG_STATIC_EX(vision_handler_cfg,
                                PBEnvelope_detected_object_tag,
                                detected_object,
                                handle_detected_object,
                                tskIDLE_PRIORITY + 3U,
                                768U,
                                16U);
```

---

###   


<details id="bkmrk-these-r-not-in-the-c"><summary>these r not in the code lol</summary>

begin here

### <span style="white-space: pre-wrap;">II) </span>`<span class="editor-theme-code">PACKET_HANDLER_CONFIG_STATIC_QUEUE</span>`

```c
#define PACKET_HANDLER_CONFIG_STATIC_QUEUE(name, packet_tag, payload_member_size, handler_fn, queue_length_)
```

Same as the basic macro, but lets you override queue length.

##### Best used when

- handler needs a longer or shorter queue
- default priority is still fine

##### Example

```c
PACKET_HANDLER_CONFIG_STATIC_QUEUE(sensor_handler_cfg,
                                   PBEnvelope_sensor_diag_tag,
                                   sensor_diag,
                                   handle_sensor_diag,
                                   12);
```

---

### <span style="white-space: pre-wrap;">III) </span>`<span class="editor-theme-code">PACKET_HANDLER_CONFIG_STATIC_PRIO</span>`

```c
#define PACKET_HANDLER_CONFIG_STATIC_PRIO(name, packet_tag, payload_member, handler_fn, priority_)
```

Same as the basic macro, but lets you override task priority.

##### Best used when

- one handler must run at a different RTOS priority
- default queue length is still fine

##### Example

```c
PACKET_HANDLER_CONFIG_STATIC_PRIO(emergency_handler_cfg,
                                  PBEnvelope_arm_obstructions_tag,
                                  arm_obstructions,
                                  handle_arm_obstructions,
                                  tskIDLE_PRIORITY + 4U);
```

---

### <span style="white-space: pre-wrap;">IV) </span>`<span class="editor-theme-code">PACKET_HANDLER_CONFIG_STATIC_PRIO_QUEUE</span>`

```c
#define PACKET_HANDLER_CONFIG_STATIC_PRIO_QUEUE(    name, packet_tag, payload_member, handler_fn, queue_length_, priority_)
```

Lets you override both:

- queue length
- task priority

##### Best used when

- a handler has non-default scheduling needs
- and also non-default backlog requirements

##### Example

```c
PACKET_HANDLER_CONFIG_STATIC_PRIO_QUEUE(nav_handler_cfg,
                                        PBEnvelope_ph_info_tag,
                                        ph_info,
                                        handle_ph_info,
                                        10,
                                        tskIDLE_PRIORITY + 3U);
```

---

end here

</details>