Use TX=GPIO3 and RX=GPIO2 at 921600 to match the terminal adapter wiring; log received message id and which handler command is triggered. Co-authored-by: Cursor <cursoragent@cursor.com>
115 lines
4.0 KiB
Markdown
115 lines
4.0 KiB
Markdown
# 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, **TX=GPIO3**, **RX=GPIO2** — USB adapter on `/dev/ttyUSB0`):
|
||
|
||
| Field | Value |
|
||
|-----------|--------------------------------------------|
|
||
| Start | `0xAA` |
|
||
| Length | 1 byte, payload size (1–252), 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 |
|