powerpods/main/README.md
simon 43a85ce697 Add command queue dispatcher and VERSION UART handler.
Centralize command dispatch over a FreeRTOS queue so UART and future
ESP-NOW transports can register handlers; implement the protobuf VERSION
command with framed nanopb responses including build git hash.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 21:46:51 +02:00

115 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Command handler
Generic command dispatch for Powerpod. Transports (UART today, ESP-NOW later) enqueue messages on a shared FreeRTOS queue; a dispatcher task invokes registered callbacks by message ID.
## Architecture
```
UART / ESP-NOW → generic_msg_t queue → vCmdDispatcherTask → registered handler
```
- **`cmd_handler`** — queue, registration, dispatcher task
- **`uart`** — framed serial input, converts packets to `generic_msg_t`
- **`powerpod.c`** — creates the queue, calls `init_cmdHandler()` then `init_uart()`
Initialize the command handler **before** UART so the dispatcher is running when packets arrive.
```c
cmd_queue = xQueueCreate(10, sizeof(generic_msg_t));
init_cmdHandler(cmd_queue);
init_uart(cmd_queue);
```
## UART frame format
Packets on UART1 (921600 baud, pins TX=2 / RX=3):
| Field | Value |
|-----------|--------------------------------------------|
| Start | `0xAA` |
| Length | 1 byte, payload size (1252), non-zero |
| Payload | `length` bytes |
| Checksum | XOR of all payload bytes |
| Stop | `0xCC` |
**Payload layout for the command handler:**
| Offset | Meaning |
|--------|----------------------------------|
| 0 | Command ID (`msg_id`, uint8/16) |
| 1… | Arguments (passed to handler) |
Example: command `0x01` with arguments `0x02 0x03` → payload `01 02 03`, length = 3.
The dispatcher strips the first byte; handlers receive only the argument bytes.
## API
### `msg_register_handler(uint16_t id, msg_callback_t cb)`
Register a callback for a command ID. Up to 32 handlers. Re-registering the same ID updates the callback.
```c
static void on_ping(const uint8_t *data, size_t len) {
ESP_LOGI("app", "ping, %u bytes", (unsigned)len);
}
msg_register_handler(0x01, on_ping);
```
Callback signature:
```c
typedef void (*msg_callback_t)(const uint8_t *data, size_t len);
```
### `msg_post(uint16_t id, const uint8_t *data, size_t len)`
Enqueue a command from firmware (e.g. ESP-NOW receive path) without UART. Copies `data` into heap memory; the dispatcher frees it after the handler returns.
```c
uint8_t args[] = {0x02, 0x03};
msg_post(0x01, args, sizeof(args));
```
Returns `ESP_OK`, `ESP_ERR_NO_MEM`, `ESP_ERR_TIMEOUT` (queue full), or `ESP_ERR_INVALID_STATE`.
## Adding a new command
1. Pick a command ID (first byte of UART payload).
2. Implement a handler in `powerpod.c` (or a dedicated module).
3. Call `msg_register_handler()` after `init_cmdHandler()`.
4. From a host tool, send a framed UART packet with that ID in byte 0.
## VERSION command (`MessageType.VERSION` = 3)
Implemented in `cmd_version.c`. Request is a UART frame with payload `03` (command byte only).
Response frame payload:
| Byte 0 | Bytes 1… |
|--------|----------|
| `0x03` | nanopb-encoded `UartMessage` with `type = VERSION` and `version_response` set |
`VersionResponse` fields:
- `version``POWERPOD_FW_VERSION` (default `1`, override at compile time)
- `git_hash` — short git hash from build (`POWERPOD_GIT_HASH`, from `git rev-parse`)
Register additional proto commands the same way: handler + `uart_send_uart_message()` for replies.
## ESP-NOW (planned)
Parse incoming ESP-NOW data in the Wi-Fi layer and call `msg_post()` with the same ID + payload layout as UART (ID separate, arguments in `data`). No changes to `cmd_handler` required.
## Files
| File | Role |
|-----------------|-------------------------------------------|
| `cmd_handler.h` | Types and public API |
| `cmd_handler.c` | Queue dispatch, registration, `msg_post` |
| `uart.c` | Framed UART parser → queue |
| `powerpod.c` | Queue creation and init order |
| `cmd_version.c` | VERSION command handler |
| `uart_proto.c` | Encode/send `UartMessage` over UART |