# Events

Every signal in the Kode Dot's firmware, grouped by the Active Object that owns it, with the event each one carries.

## What it is

Active Objects talk only through events. An event is a signal, a number that
says what happened or what is asked, plus a small struct of data copied into
it. This page lists every signal the SDK and kodeOS define, one table per
owner, so you can find what to subscribe to and what to post.

## How it is connected

```mermaid
flowchart LR
  subgraph pubs["Published: below MAX_PUB_SIG"]
    pub["An owner"] -- "publish" --> any["Every subscriber"]
  end
  subgraph posts["Posted: at or above MAX_PUB_SIG"]
    req["Your AO"] -- "post" --> own["One owner"]
    own -. "reply to who" .-> req
  end
  class pub ao
  class any ao
  class req app
  class own ao
```

*Two ways an event travels*

Each table is one owner. How to read its columns:

- **Range** is `publish` for a signal below `MAX_PUB_SIG` and `post` for one at or above it.
- **Event** names the struct the signal carries. A bare `QEvt` is made once as a `static const` and takes no pool block, so it cannot fail to allocate.

Three more rules help when you read a table:

- Replies go to the `QActive *who` the request carried.
- The private timers are `QTimeEvt` members of the owner and nobody else sends them.
- A `*_TEST_REQ_SIG` runs a row of the console's `test`. The verdict returns as a published `TEST_RESULT_SIG` or `TEST_SKIP_SIG`, after the row's own step signals when it has them.

The signals are numbered in `kqp_signals.h`, and the structs they carry are declared in the same file. `kqp.c` checks with `_Static_assert` that each struct fits the pool block it is allocated from, so an event that grows too big fails the build instead of the board.

`sdk/kqp` explains the pools that hold the events and the priorities that decide who runs first.

## Specifications

### AO_LedMgr

Every signal AO_LedMgr owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `LED_SET_SIG` | publish | `LedEvt` | Light the LED (last colour, or white) or darken it, by `on`. |
| `LED_TOGGLE_SIG` | publish | `LedEvt` | Invert the LED. `on` is unused. |
| `LED_BLINK_PERIOD_SIG` | publish | `LedBlinkEvt` | Set the heartbeat period. |
| `LED_HEARTBEAT_ENABLE_SIG` | publish | `LedEvt` | Start or stop the heartbeat, by `on`. |
| `LED_RGB_SIG` | publish | `LedRgbEvt` | Set the colour; (0, 0, 0) is off. |
| `LED_TEST_SIG` | publish | `LedTestEvt` | One step of the LED row: a colour to judge or its outcome. |
| `LED_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=led`; the verdict returns as `TEST_RESULT_SIG`. |
| `LED_HEARTBEAT_SIG`, `LED_TEST_WAIT_SIG` | post | `QTimeEvt` | Private timers, in order: the heartbeat blink; nobody answered the colour in time. |

### AO_AppMgr

Published signals: every Active Object that subscribed hears them.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `APP_FLASH_DONE_SIG` | publish | `AppFlashDoneEvt` | A write ended well; `name` is the app installed, empty for the C5 image. AO_Radio publishes it too. |
| `APP_FLASH_FAIL_SIG` | publish | `AppFlashFailEvt` | A write failed. AO_Radio publishes it too. |
| `APP_FLASH_PROGRESS_SIG` | publish | `AppProgressEvt` | 0 % when a write starts, then each whole percent, with the file and what is written. The Opening sheet and the LED follow a write by this family. |
| `APP_ENTRY_SIG` | publish | `AppEntryEvt` | One installed app, in answer to `APP_LIST_REQ_SIG`. |
| `APP_LIST_END_SIG` | publish | `ListEndEvt` | The last entry of the page; `more` says another page follows. |
| `APP_EVICTED_SIG` | publish | `AppEvictedEvt` | An install took this app's place in the region, one event per app, before the write starts; `kept` says a copy is on the card. The app being replaced is not one. |
| `APP_CAT_RSP_SIG` | publish | `AppCatRspEvt` | The outcome of `APP_CAT_REQ_SIG`. |

### AO_AppMgr: posted signals

Posted signals go to one Active Object: requests, replies to the asker, and the private signals and timers.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `APP_FLASH_CHUNK_SIG` | post | bare `QEvt` | Private: pace the next chunk of a write. |
| `APP_ADOPT_SIG` | post | bare `QEvt` | Private: the `app_pending` mailbox holds a verified image at boot; adopt it. |
| `APP_ERASE_REQ_SIG` | post | `AppFlashEvt` | Remove the named app from the region. |
| `APP_CAT_REQ_SIG` | post | `AppCatReqEvt` | Assign or drop an app's categories. |
| `APP_RUN_REQ_SIG` | post | `AppFlashEvt` | Boot the named installed app; the board resets. |
| `APP_LIST_REQ_SIG` | post | `AppListReqEvt` | Post `APP_ENTRY_SIG` for a page of installed apps to the asker, then `APP_LIST_END_SIG`. |
| `APP_EVICT_REQ_SIG` | post | `AppEvictReqEvt` | Ask which installed apps an install of this size and name would evict. |
| `APP_EVICT_ENTRY_SIG` | post | `AppEvictEntryEvt` | To the asker: one app the install would evict, in eviction order. |
| `APP_EVICT_END_SIG` | post | `AppEvictEndEvt` | To the asker: the last entry. |
| `APP_RECV_REQ_SIG` | post | `AppRecvReqEvt` | An image is about to arrive on the console, for the region, the inactive OS slot or the mailbox. |
| `FLASH_REQ_SIG` | post | `FlashReqEvt` | One source-to-sink transfer. The only way to ask for an image to be written. |
| `APP_RECV_IDLE_SIG`, `APP_RECV_LAUNCH_SIG` | post | `QTimeEvt` | Private timers, in order: no chunk for `KODE_RECV_IDLE_MS`, the host is gone; the drain delay after a good install is over, boot it. |

### Console receive protocol

The signals of a payload that arrives on the console.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `RECV_READY_SIG` | publish | bare `QEvt` | The destination is open and the console is in raw mode: the host may stream. Becomes `>\|ready`. |
| `RECV_ACK_SIG` | publish | bare `QEvt` | One full chunk was consumed: the host may send the next (`>\|ack`). The whole flow control of a transfer. AO_Console alone hears it. |
| `RECV_DONE_SIG` | publish | bare `QEvt` | The payload arrived and verified. A terminal install is installed; a `file_put` is a file on FAT. |
| `RECV_FAIL_SIG` | publish | bare `QEvt` | Refused, or the bytes did not survive the trip. |
| `RECV_STALL_SIG` | publish | bare `QEvt` | The host stopped sending and never came back. |
| `RECV_DATA_SIG` | post | `RecvDataEvt` | One chunk of the payload, from AO_Console to the receiving AO. |

### AO_Storage

Published signals: every Active Object that subscribed hears them.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `STORAGE_ENTRY_SIG` | publish | `StorageEntryEvt` | One file found by `sd_ls`, `fs_ls` or `ls`. |
| `STORAGE_LIST_END_SIG` | publish | `ListEndEvt` | The last entry of the page. |
| `STORAGE_INFO_SIG` | publish | `StorageInfoEvt` | One medium's mount state and usage. |
| `STORAGE_TEST_SIG` | publish | `StorageTestEvt` | One phase of the card test, with what it measured. |

### AO_Storage: posted signals

Posted signals go to one Active Object: requests, replies to the asker, and the private signals and timers.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `STORAGE_CMD_SIG` | post | `StorageCmdEvt` | Run one command (`op`) on a medium. |
| `STORAGE_LIST_PAGE_SIG` | post | `StorageListPageEvt` | Post a page of the bootable images on every medium to the asker. |
| `STORAGE_CMD_RSP_SIG` | post | bare `QEvt` | To `who`: the command has run. |
| `STORAGE_OPEN_REQ_SIG` | post | `StorageOpenEvt` | Open a named file for reading. |
| `STORAGE_READ_REQ_SIG` | post | bare `QEvt` | Fill a free buffer and send it. |
| `STORAGE_NEXT_SIG` | post | `StorageBufEvt` | A borrowed buffer handed back: refill it and send it again. |
| `STORAGE_CLOSE_REQ_SIG` | post | bare `QEvt` | Close the open file. |
| `STORAGE_OPEN_RSP_SIG` | post | `StorageOpenRspEvt` | To the opener: whether the file is open. |
| `STORAGE_DATA_SIG` | post | `StorageDataEvt` | To the reader: one buffer of the file. |
| `STORAGE_WRITE_REQ_SIG` | post | `StorageWriteEvt` | Put a caller's data in a file, in one event. |
| `STORAGE_WRITE_RSP_SIG` | post | `StorageWriteRspEvt` | To the writer: how the write ended. |
| `STORAGE_DESC_REQ_SIG` | post | `StorageDescReqEvt` | Read the manifest out of the front of one file. |
| `STORAGE_DESC_RSP_SIG` | post | `StorageDescRspEvt` | That file's identity, back to `who`. |
| `APPDATA_REQ_SIG` | post | `AppDataReqEvt` | Resolve an app's data folder. |
| `APPDATA_FIELDS_SIG` | post | `AppDataFieldsEvt` | To the asker: the folder's fields. |
| `APPDATA_ICON_SIG` | post | `AppDataIconEvt` | To the asker: one third of the icon. |
| `APPDATA_END_SIG` | post | bare `QEvt` | To the asker: the conversation is over. |
| `APPDATA_RM_REQ_SIG` | post | `AppDataReqEvt` | Delete one app's data folder on the internal partition. |
| `APPDATA_RM_RSP_SIG` | post | `AppDataRmRspEvt` | To the asker: how the delete ended. |
| `STORAGE_FIELD_REQ_SIG` | post | `StorageFieldReqEvt` | Read, write or dump one field of the card's table. |
| `STORAGE_FIELD_RSP_SIG` | post | `StorageFieldEvt` | To the requester: the field. |
| `STORAGE_PATH_REQ_SIG` | post | `StoragePathEvt` | Stat, list, cat, mkdir, unlink or rmdir one path. |
| `STORAGE_PATH_RSP_SIG` | post | `StoragePathRspEvt` | To the requester: the answer of stat, mkdir, unlink, rmdir and move. |
| `STORAGE_LINE_SIG` | post | `StorageLineEvt` | To the requester of `cat`: one line of the file, or the terminator. |
| `STORAGE_PAIR_REQ_SIG` | post | `StoragePairEvt` | Move or copy a source to a destination. |
| `STORAGE_TEXT_REQ_SIG` | post | `StorageTextEvt` | Put text in a file. |
| `STORAGE_LEND_REQ_SIG` | post | `StorageLendEvt` | Lend the card for sector access, or take it back. |
| `STORAGE_RECV_REQ_SIG` | post | `StorageRecvEvt` | A file is about to arrive on the console (`file_put`). |
| `STORAGE_SDJOB_DONE_SIG` | post | `KqpWorkerDoneEvt` | `storage_sd` to AO_Storage: a call to the card returned. |
| `STORAGE_WRITE_NEXT_SIG`, `STORAGE_TEST_NEXT_SIG`, `STORAGE_CAT_NEXT_SIG`, `STORAGE_COPY_NEXT_SIG`, `STORAGE_RECV_IDLE_SIG`, `STORAGE_SDJOB_TO_SIG` | post | `QTimeEvt` | Private timers, in order: the next chunk of a write; the next step of the card test; the next batch of lines of a `cat`; the next chunk of a `cp`; no chunk of an arriving file for `KODE_RECV_IDLE_MS`; a call to the card did not return in time. |

### AO_Autotest

Every signal AO_Autotest owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `TEST_RESULT_SIG` | publish | `TestResultEvt` | Any AO: the outcome of a self-test that could not be answered on the spot. It carries the `origin` of the run, and AO_Autotest ignores a verdict that is not its own. |
| `TEST_SKIP_SIG` | publish | `TestResultEvt` | Any AO: a self-test that could not be judged because what it needs is absent (no card, no cable, no tag). `ok` is unused. |
| `AUTOTEST_BEGIN_SIG` | publish | `AutotestBeginEvt` | A run was taken or refused. |
| `AUTOTEST_ROW_SIG` | publish | `AutotestRowEvt` | One row started or ended. |
| `AUTOTEST_END_SIG` | publish | `AutotestEndEvt` | The run is over. |
| `AUTOTEST_HOLD_SIG` | publish | `AutotestHoldEvt` | The run waits for whoever asked, before the rows that need hands. |
| `AUTOTEST_REPORT_SIG` | publish | `AutotestReportEvt` | One row of the report kept from the last `user` run, then an end marker. |
| `PSRAM_TEST_SIG` | publish | `PsramTestEvt` | What the PSRAM row tested and found, once per run, before its verdict. |
| `AUTOTEST_RUN_REQ_SIG` | post | `AutotestRunReqEvt` | Run a group of rows, or one by name. |
| `AUTOTEST_CANCEL_REQ_SIG` | post | `AutotestClientEvt` | End the run in flight after the row in flight. |
| `AUTOTEST_CONTINUE_SIG` | post | `AutotestClientEvt` | The answer to a hold. |
| `AUTOTEST_REPORT_REQ_SIG` | post | `AutotestClientEvt` | Publish the kept report. |
| `AUTOTEST_PSRAM_STEP_SIG`, `AUTOTEST_BUDGET_SIG` | post | `QTimeEvt` | Private timers, in order: the PSRAM row's next step is due; the row in flight ran out of budget, or nobody answered a hold. |

### AO_Power

Every signal AO_Power owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `POWER_EVT_SIG` | publish | `PowerEvt` | A battery reading. |
| `POWER_SHIP_SIG` | publish | bare `QEvt` | The BATFET is about to open (ship mode). Published in the step before the write, so every owner can prepare. |
| `POWER_FIELD_SIG` | publish | `PowerFieldEvt` | One chip field's value, or the outcome of writing it. |
| `POWER_CTRL_SIG` | publish | `PowerCtrlEvt` | The answer to one `POWER_CTRL_REQ_SIG`, a refusal included. |
| `POWER_TEST_SIG` | publish | `PowerTestEvt` | One step of the `power_plug` row. |
| `POWER_DUMP_REQ_SIG` | post | bare `QEvt` | Log everything both chips say. |
| `POWER_PEEK_REQ_SIG` | post | bare `QEvt` | One quiet reading, published as `POWER_EVT_SIG`, with the wall clock kept. AO_LowPower asks once a minute while the board is ASLEEP. |
| `POWER_SHIP_REQ_SIG` | post | bare `QEvt` | Ship mode: open the BATFET and cut the battery from VSYS. The console verb `ship_mode` posts it. |
| `POWER_SHIP_ARM_SIG` | post | `PowerShipArmEvt` | Count `KODE_SHIP_UNPLUG_MS` from the cable leaving, then tell the asker. |
| `POWER_SHIP_DUE_SIG` | post | bare `QEvt` | To the asker of the arming: the cable has been out for `KODE_SHIP_UNPLUG_MS`. |
| `POWER_FIELD_REQ_SIG` | post | `PowerFieldReqEvt` | Read, write or dump one field of the PMIC or the gauge. |
| `POWER_TEST_REQ_SIG` | post | `PowerTestReqEvt` | Run `test component=pmic` or `gauge`. |
| `POWER_CTRL_REQ_SIG` | post | `PowerCtrlReqEvt` | One owner-level operation on the PMIC: boost, charge, charge limit, reset. |
| `POWER_POLL_SIG`, `POWER_PULSE_SIG`, `POWER_CTRL_TICK_SIG`, `POWER_TEST_STEP_SIG`, `POWER_SHIP_TMO_SIG` | post | `QTimeEvt` | Private timers, in order: the poll; the next half of the write pulse of the LED; the one-shot wait of `Power_waiting` is over; the `power_plug` row looks at the cable again; the countdown after the cable left is over. |

### AO_LowPower

Present only with `CONFIG_KODE_LOWPOWER`. The three published signals are the protocol of the board's rest (`sdk/kaos/lowpower`).

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `LOWPOWER_ROUND_SIG` | publish | `LowPowerRoundEvt` | A round of readiness is open for a target state, ASLEEP or OFF. Each owner that joined rests its device and answers once with `lowpower_ready()`. |
| `LOWPOWER_STATE_SIG` | publish | `LowPowerStateEvt` | The board changed state: `state` is AWAKE, ASLEEP, OFF or RADIO, with the `cause` and the `prev` state. State AWAKE also arrives with `prev` AWAKE when a round was abandoned, so the restore must be idempotent. Arm no `QTimeEvt` on state ASLEEP. State RADIO is for the owners of `lowpower_join_radio()` alone. |
| `LOWPOWER_REFUSED_SIG` | publish | `LowPowerRefusedEvt` | A request or a round did not go through. `src` says whose request it answers, and `why` is `who: why`, a copy. |
| `LOWPOWER_REQ_SIG` | post | `LowPowerReqEvt` | Go to a state. From the console verbs `sleep` and `power_off`, from `kode_power_sleep()` and `kode_power_off()`, and from AO_Radio when its sentinel could not go back down. |
| `LOWPOWER_READY_SIG` | post | `LowPowerReadyEvt` | One participant's answer to a round: `who`, `round`, `busy` and a reason copy. |
| `LOWPOWER_INPUT_SIG` | post | `LowPowerInputEvt` | A console line came in. One static event for each port, so a wake from BLE or the channel is never lost to an empty pool. |
| `LOWPOWER_REST_SIG` | post | `LowPowerReqEvt` | An owner whose time woke the board (AO_Scheduler) asks to sleep again, unless somebody used the board. |
| `LOWPOWER_WAKE_AT_SIG` | post | `LowPowerWakeAtEvt` | An owner's work falls due at a real time (`khal_time_us()`). Asleep, the board wakes for it. |
| `LOWPOWER_RADIO_DONE_SIG` | post | `LowPowerRadioDoneEvt` | A radio owner's work in a radio wake is finished. |
| `LOWPOWER_MINUTE_SIG` | post | bare `QEvt` | The minute timer of ASLEEP ran out. A static event, posted from the callback of `khal_timer_once()`. |
| `LOWPOWER_ROUND_TMO_SIG`, `LOWPOWER_IDLE_TMO_SIG`, `LOWPOWER_RADIO_TMO_SIG`, `LOWPOWER_RETRY_TMO_SIG`, `LOWPOWER_STATE_RETRY_SIG` | post | `QTimeEvt` | Private timers, in order: a round's budget, or the grace before OFF; the idle time; the bound of a radio wake; the wait before a requested round begins again; a state change that found no event is published again. |

It subscribes to `IOEXP_INPUT_SIG`, `BUTTON_EVT_SIG`, `TOUCH_EVT_SIG`, `POWER_EVT_SIG`, `MQTT_MSG_SIG` and `CONFIG_REQ_SIG`.

### AO_Scheduler

Present only with `CONFIG_KODE_SCHEDULER` (`sdk/kaos/scheduler`).

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `SCHED_SET_REQ_SIG` | post | `SchedSetReqEvt` | Make or change a console entry. `when` of `off` removes it, or switches `mqtt` off. |
| `SCHED_SET_AO_REQ_SIG` | post | `SchedSetAoReqEvt` | Make or change an entry that posts an event to an Active Object. |
| `SCHED_REMOVE_REQ_SIG` | post | `SchedNameReqEvt` | Remove an entry of code. |
| `SCHED_LIST_REQ_SIG` | post | `SchedNameReqEvt` | One entry, or every entry when the name is empty. |
| `SCHED_ENTRY_SIG` | post | `SchedEntryEvt` | To the asker: one entry (`owner`, `stored`, `next_s`, `name`, `when`, `cmd`). The widest tenant of the large pool. |
| `SCHED_END_SIG` | post | `SchedEndEvt` | To the asker: the request is answered (`st`, `why`, `count`). |
| `SCHED_LINE_DONE_SIG` | post | bare `QEvt` | The console answered the line it was given, so the next may go. |
| `SCHED_CHECK_DONE_SIG` | post | `SchedCheckDoneEvt` | AO_Net made the check of the `mqtt` entry. |
| `SCHED_UP_SIG` | post | bare `QEvt` | From `kode_init()`: every Active Object has its queue, so the scheduler may post. |
| `SCHED_DUE_SIG`, `SCHED_WORK_TMO_SIG` | post | `QTimeEvt` | Private timers, in order: the earliest minute is near, or the clock is asked again; the work of a minute ran `KODE_SCHED_WORK_BOUND_MS`. |

An entry of code fires as a `SchedFireEvt` (`name`) with the signal that the entry named. AO_Scheduler subscribes to `LOWPOWER_ROUND_SIG`, `LOWPOWER_STATE_SIG` and `LOWPOWER_REFUSED_SIG` when `CONFIG_KODE_LOWPOWER` is on.

### AO_Display

Published signals: every Active Object that subscribed hears them.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `DISPLAY_STATE_SIG` | publish | `DisplayStateEvt` | Whether the panel is up and how bright it is driven. Published once at startup and again for each `DISPLAY_STATE_REQ_SIG`. |
| `DISPLAY_MIRROR_INFO_SIG` | publish | `MirrorInfoEvt` | The mirror's live state. |
| `DISPLAY_TEST_SIG` | publish | `DisplayTestEvt` | One step of the display row. |
| `DISPLAY_REPAINT_SIG` | publish | bare `QEvt` | The display row is over, or the glass came back from a rest with new framebuffers (`CONFIG_KODE_LOWPOWER`). Whoever draws the glass fetches its buffers again and invalidates all of it. |

### AO_Display: posted signals

Posted signals go to one Active Object: requests, replies to the asker, and the private signals and timers.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `DISPLAY_FLUSH_SIG` | post | `FlushEvt` | Push one rendered rectangle to the panel. |
| `DISPLAY_BRIGHTNESS_SIG` | post | `BrightnessEvt` | Set the brightness, in percent. |
| `DISPLAY_STATE_REQ_SIG` | post | bare `QEvt` | Publish `DISPLAY_STATE_SIG` again, for whoever started late. |
| `DISPLAY_CAPTURE_REQ_SIG` | post | `DisplayCaptureReqEvt` | Copy the frame on the glass and say how big it is. |
| `DISPLAY_CAPTURE_RSP_SIG` | post | `DisplayCaptureRspEvt` | To the requester: the copy. |
| `DISPLAY_CAPTURE_END_SIG` | post | bare `QEvt` | The capture is done with the buffer; the flush path may write it again. |
| `DISPLAY_MIRROR_START_SIG` | post | `MirrorStartEvt` | Begin streaming the panel; the next frame is the whole panel. |
| `DISPLAY_MIRROR_STOP_SIG` | post | bare `QEvt` | Stop streaming. |
| `DISPLAY_MIRROR_ACK_SIG` | post | `MirrorAckEvt` | The host has received up to `seq`; releases credit. |
| `DISPLAY_MIRROR_INFO_REQ_SIG` | post | bare `QEvt` | Publish `DISPLAY_MIRROR_INFO_SIG`. |
| `DISPLAY_SHOT_REQ_SIG` | post | `DisplayShotReqEvt` | Encode the front framebuffer whole as one JPEG and lend it. |
| `DISPLAY_SHOT_RSP_SIG` | post | `DisplayShotRspEvt` | To the requester: the JPEG. |
| `DISPLAY_SHOT_END_SIG` | post | bare `QEvt` | The requester is done with the shot; take the buffer back. |
| `DISPLAY_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=display`. |
| `DISPLAY_TEST_STEP_SIG` | post | bare `QEvt` | Private, self-posted: paint the next band of the field. |
| `DISPLAY_MINUTE_REQ_SIG` | post | bare `QEvt` | With `CONFIG_KODE_LOWPOWER`, from AO_LowPower each minute while ASLEEP: write the time into the panel's memory. |
| `DISPLAY_GLYPHS_SIG` | post | `DisplayGlyphsEvt` | With `CONFIG_KODE_LOWPOWER`, from `display_glyphs_hand()`: the renderer has stopped, and here is the strip of digits (a pointer into the renderer's PSRAM, an exception to the rule that events carry copies). |
| `DISPLAY_MIRROR_TICK_SIG`, `DISPLAY_TEST_WAIT_SIG`, `DISPLAY_GLYPHS_TMO_SIG`, `DISPLAY_RESTORE_SIG` | post | `QTimeEvt` | Private timers, in order: the mirror's pacer, re-armed after each pass; nobody answered the field in time; the renderer handed no glyphs in `KODE_LOWPOWER_GLYPHS_WAIT_MS`; the glass could not be put back and is tried again. |

### AO_Touch

Every signal AO_Touch owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `TOUCH_EVT_SIG` | publish | `TouchEvt` | A touch sample, pinned to the glass. |
| `TOUCH_TEST_SIG` | publish | `TouchTestEvt` | One step of the guided touch test: a target to tap, or its outcome. |
| `TOUCH_FIELD_REQ_SIG` | post | `TouchFieldReqEvt` | Read, write or dump one field of the CST820. |
| `TOUCH_FIELD_RSP_SIG` | post | `TouchFieldEvt` | To the requester: the field. |
| `TOUCH_TEST_REQ_SIG`, `TOUCH_TEST_REQ_FROM_SIG` | post | bare `QEvt`, `TestReqEvt` | Run `test component=tp`. The second names who asked (`origin`), and every step and the verdict carry it back. |
| `TOUCH_POLL_SIG`, `TOUCH_TEST_TMO_SIG`, `TOUCH_RESTORE_SIG` | post | `QTimeEvt` | Private timers, in order: the poll while a finger is down; the operator did not tap the target in time; with `CONFIG_KODE_LOWPOWER`, the controller is written back to its awake settings again. |

### AO_Buttons

Every signal AO_Buttons owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `BUTTON_EVT_SIG` | publish | `ButtonEvt` | One button changed. |
| `BUTTON_HOLD_SIG` | publish | `ButtonHoldEvt` | TOP or BOT has been down for `KODE_BUTTON_HOLD_MS`. |
| `BUTTON_DOUBLE_SIG` | publish | `ButtonDoubleEvt` | TOP was pressed twice in quick succession. |
| `BTN_STATE_SIG` | publish | `ButtonsStateEvt` | All six buttons now, in answer to `BUTTONS_DUMP_REQ_SIG`. |
| `BTN_TEST_SIG` | publish | `ButtonsTestEvt` | One step of the guided button test. |
| `BUTTONS_DUMP_REQ_SIG` | post | bare `QEvt` | Log every button's state. |
| `BUTTONS_TOP_INT_SIG` | post | bare `QEvt` | Private: GPIO35 moved. Posted from the pin's interrupt through `kqp_post_from_isr()`. |
| `BUTTONS_TEST_REQ_SIG`, `BUTTONS_TEST_REQ_FROM_SIG` | post | bare `QEvt`, `TestReqEvt` | Run `test component=buttons`. The second names who asked (`origin`), and every step and the verdict carry it back. |
| `BUTTONS_ROTATE_SIG` | post | `ButtonsRotateEvt` | Turn the pad by quarter turns, from `buttons_rotation_request()`. |
| `BUTTONS_PAD_IDLE_SIG` | post | bare `QEvt` | Private: an injected release left the pad idle, so a turn that waited may apply. |
| `BUTTONS_SETTLE_SIG`, `BUTTONS_TEST_TMO_SIG`, `BUTTONS_HOLD_TMO_SIG` | post | `QTimeEvt` | Private timers, in order: A change was seen, take the confirming sample; the operator did not press the button in time; a button has been down for `KODE_BUTTON_HOLD_MS`. |

### AO_Boot

Every signal AO_Boot owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `HOME_SIG` | publish | bare `QEvt` | The bottom button was held: the interface goes home. Published in both roles. |
| `BOOT_STATE_SIG` | publish | `BootStateEvt` | The boot state, in answer to `BOOT_INFO_REQ_SIG`. |
| `BOOT_OS_SWITCH_SIG` | post | bare `QEvt` | Point otadata at the inactive kodeOS slot and reset. |
| `BOOT_APP_RUN_SIG` | post | `BootRunEvt` | Write a boot request (NEW or ALWAYS, by `mode`) and reset so the bootloader jumps. |
| `BOOT_INFO_REQ_SIG` | post | bare `QEvt` | Log the boot state. |
| `BOOT_EXIT_REQ_SIG` | post | bare `QEvt` | Reset. In an app this is the way home. |
| `BOOT_HOME_DEFER_SIG` | post | bare `QEvt` | The app asks for a moment before the hold resets it, from `kode_home_defer()`. |
| `BOOT_HOME_NOW_SIG` | post | bare `QEvt` | The app is ready, go home now, from `kode_home_now()`. |
| `BOOT_RADIO_PARKED_SIG` | post | bare `QEvt` | Private, from `boot_radio_parked()`: AO_Radio has done with the C5 for the jump. |
| `BOOT_NET_LEFT_SIG` | post | bare `QEvt` | Private, from `boot_net_left()`: AO_Net has left the Kode channel for the jump. |
| `BOOT_HOME_GRACE_SIG`, `BOOT_LEAVE_TMO_SIG` | post | `QTimeEvt` | Private timers, in order: the grace is over (or, once extended, the cap); the step of the leave that is running ran out of time. |

### AO_IoExp

Every signal AO_IoExp owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `IOEXP_INPUT_SIG` | publish | `IoexpInputEvt` | What the expander's eight pins read. Published on every read of the input register. |
| `IOEXP_INT_SIG` | post | bare `QEvt` | Private: the TCA6408A's INT line went low. |
| `IOEXP_READ_REQ_SIG` | post | bare `QEvt` | Read the input register now and publish `IOEXP_INPUT_SIG`, changed or not. |
| `IOEXP_FIELD_REQ_SIG` | post | `IoexpFieldReqEvt` | Read, write or dump one field of the expander. |
| `IOEXP_FIELD_RSP_SIG` | post | `IoexpFieldEvt` | To the requester: the field. |
| `IOEXP_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=ioexp`. |
| `IOEXP_RETRY_SIG` | post | `QTimeEvt` | Private timers, in order: INT fired and the input register did not read: ask again. |

### AO_Ir

Every signal AO_Ir owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `IR_RX_SIG` | publish | `IrRxEvt` | One frame the receiver heard. Not published for a frame this board sent itself. |
| `IR_SEND_REQ_SIG` | post | `IrSendEvt` | Transmit one NEC frame. |
| `IR_SEND_RAW_REQ_SIG` | post | `IrSendRawEvt` | Transmit the frame the requester lends, on its carrier. |
| `IR_CAPTURE_REQ_SIG` | post | `IrCaptureEvt` | Fill the requester's buffer with the next frame heard. |
| `IR_INFO_REQ_SIG` | post | `IrInfoReqEvt` | The console's `ir`: the block's own status. |
| `IR_INFO_RSP_SIG` | post | `IrInfoEvt` | To the requester: the status. |
| `IR_LAST_REQ_SIG` | post | `IrLastEvt` | The last frame heard, written into the requester's memory and signalled on a semaphore. |
| `IR_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=ir`. |
| `IR_RX_RDY_SIG` | post | bare `QEvt` | Private: a capture is waiting in the driver. Posted from the receive interrupt. |
| `IR_JOB_DONE_SIG` | post | `KqpWorkerDoneEvt` | `ir_worker` to AO_Ir: a call to the C5 returned. |
| `IR_ECHO_SIG`, `IR_CAPTURE_TO_SIG`, `IR_TEST_TO_SIG`, `IR_JOB_TO_SIG` | post | `QTimeEvt` | Private timers, in order: the echo-suppression window closed; the pending capture reached its deadline; an attempt of the production row heard nothing; a call to the C5 did not return in time. |

### AO_Nfc

Published signals: every Active Object that subscribed hears them.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `NFC_TAG_SIG` | publish | `NfcTagEvt` | One tag the poller activated. Published only while a request is in flight. |
| `NFC_EMU_SIG` | publish | `NfcEmuEvt` | One turn of an emulation window: a field arriving, a select, a read. |

### AO_Nfc: posted signals

Posted signals go to one Active Object: requests, replies to the asker, and the private signals and timers.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `NFC_READ_REQ_SIG` | post | `NfcReadEvt` | Energise and answer with the first tag activated inside the window. |
| `NFC_NDEF_REQ_SIG` | post | `NfcNdefEvt` | Read or write an NDEF message on the first tag activated. |
| `NFC_NDEF_RSP_SIG` | post | `NfcNdefRspEvt` | To the requester: the NDEF answer. |
| `NFC_INFO_REQ_SIG` | post | `NfcInfoReqEvt` | The console's `nfc`: the reader's status. |
| `NFC_INFO_RSP_SIG` | post | `NfcInfoEvt` | To the requester: the status. |
| `NFC_KEYS_REQ_SIG` | post | `NfcKeysReqEvt` | Sweep the public Mifare key dictionary against one block. |
| `NFC_KEYS_RSP_SIG` | post | `NfcKeysRspEvt` | To the requester: which key opened it. |
| `NFC_DUMP_REQ_SIG` | post | `NfcDumpReqEvt` | Read every sector a Mifare Classic opens and stream it, one sector per tick. |
| `NFC_DUMP_RSP_SIG` | post | `NfcDumpRspEvt` | To the requester: the dump is finished. |
| `NFC_FIELD_REQ_SIG` | post | `NfcFieldEvt` | Listen for a window with the reader's own field off and describe the field somebody else put on the antenna. |
| `NFC_FIELD_RSP_SIG` | post | `NfcFieldRspEvt` | To the requester: the window's statistics. |
| `NFC_EMU_REQ_SIG` | post | `NfcEmuReqEvt` | Present the Kode Dot as a passive NFC-A card, or stop. |
| `NFC_EMU_RSP_SIG` | post | `NfcEmuRspEvt` | To the console: a start or stop finished. |
| `NFC_CERT_REQ_SIG` | post | `NfcCertEvt` | Raise, switch or drop the held maximum-drive field. Posted only in a build with `KODEOS_NFC_CERT`. |
| `NFC_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=nfc`. |
| `NFC_TICK_SIG`, `NFC_DEADLINE_SIG` | post | `QTimeEvt` | Private timers, in order: pump `rfalNfcWorker()` once and arm again; the request in flight reached its window. |

### AO_Rfid

Every signal AO_Rfid owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `RFID_TAG_SIG` | publish | `RfidTagEvt` | One EM4100 ID decoded inside a window. Published only while a request is in flight. |
| `RFID_READ_REQ_SIG` | post | `RfidReqEvt` | Energise and report the first EM4100 ID decoded inside the window. |
| `RFID_WRITE_REQ_SIG` | post | `RfidWriteReqEvt` | Clone a 5-byte ID onto a T5577. |
| `RFID_INFO_REQ_SIG` | post | `RfidInfoReqEvt` | The console's `rfid`. |
| `RFID_INFO_RSP_SIG` | post | `RfidInfoEvt` | To the requester: the status. |
| `RFID_OP_RSP_SIG` | post | `RfidOpRspEvt` | To the console: a `rfid_read` or `rfid_write` finished. |
| `RFID_FIELD_REQ_SIG` | post | `RfidFieldEvt` | Read the demod line for a window with the carrier off and describe it. |
| `RFID_FIELD_RSP_SIG` | post | `RfidFieldRspEvt` | To the requester: the window's statistics, by value. |
| `RFID_CERT_REQ_SIG` | post | `RfidCertEvt` | Raise, switch or drop the held maximum-drive 125 kHz carrier. Posted only with `KODEOS_NFC_CERT`. |
| `RFID_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=rfid`. |
| `RFID_WORKER_DONE_SIG` | post | `KqpWorkerDoneEvt` | `rfid_worker` to AO_Rfid: the job finished. |
| `RFID_DEADLINE_SIG` | post | `QTimeEvt` | Private timers, in order: the request's window is over. |

### AO_Audio

Every signal AO_Audio owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `AUDIO_TEST_SIG` | publish | `AudioTestEvt` | One step of the audio row. |
| `AUDIO_FILE_RSP_SIG` | publish | `AudioFileRspEvt` | A recording reached a file, or did not. |
| `AUDIO_FIELD_SIG` | publish | `AudioFieldEvt` | One codec field's value, or the outcome of writing it. |
| `AUDIO_DONE_SIG` | publish | `AudioDoneEvt` | One play ended. |
| `AUDIO_TONE_REQ_SIG` | post | `AudioToneEvt` | Emit one tone, snapped to a detector bin. |
| `AUDIO_FIELD_REQ_SIG` | post | `AudioFieldReqEvt` | Read, write or dump one field of the codec. |
| `AUDIO_INFO_REQ_SIG` | post | `AudioInfoReqEvt` | What the audio path is and what it is set to. |
| `AUDIO_REC_FILE_REQ_SIG` | post | `AudioFileReqEvt` | Record for a while into a file. |
| `AUDIO_PLAY_REQ_SIG` | post | `AudioBufEvt` | Play the frames in the event and wake the waiter. From a task, never an Active Object. |
| `AUDIO_REC_REQ_SIG` | post | `AudioBufEvt` | Fill the event's buffer and wake the waiter. |
| `AUDIO_STREAM_OPEN_REQ_SIG` | post | `AudioBufEvt` | Open the stream; wake the waiter once it plays. |
| `AUDIO_STREAM_CLOSE_REQ_SIG` | post | `AudioBufEvt` | End the stream; wake the waiter once what it held has been heard. |
| `AUDIO_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=audio`. |
| `AUDIO_JOB_SIG` | post | `KqpWorkerDoneEvt` | The codec worker finished a job. |
| `AUDIO_GUARD_SIG` | post | `QTimeEvt` | Private timers, in order: A job handed to the worker never answered. |

### AO_Imu

Every signal AO_Imu owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `IMU_TEST_SIG` | publish | `ImuTestEvt` | One step of the IMU row. |
| `MAG_TEST_SIG` | publish | `MagTestEvt` | One step of the magnetometer row. |
| `IMU_READ_REQ_SIG` | post | `ImuReadEvt` | One sample into the caller's own struct, answered inside the step that receives it. |
| `IMU_CAPTURE_REQ_SIG` | post | `ImuCaptureReqEvt` | Arm the FIFO for the witness window of the haptic row. |
| `IMU_ARMED_SIG` | post | `ImuArmedEvt` | To whoever asked: the FIFO is armed. |
| `IMU_DRAIN_REQ_SIG` | post | `ImuDrainReqEvt` | Drain what the FIFO holds and measure it at a rate. |
| `IMU_ENERGY_SIG` | post | `ImuEnergyEvt` | To whoever asked: the energy measured. |
| `MAG_READ_REQ_SIG` | post | `MagReadEvt` | One magnetometer sample into the caller's own `int32_t[3]`. |
| `IMU_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=imu`. |
| `MAG_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=mag`. |
| `IMU_WAIT_SIG`, `IMU_REST_SIG`, `MAG_REST_SIG` | post | `QTimeEvt` | Private timers, in order: A self-test's poll, a chunk of a witness window or the gyroscope's turn-on; the IMU rests after `KODE_IMU_REST_AFTER_MS`; the same for the QMC5883P. |

### AO_Haptic

Every signal AO_Haptic owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `HAPTIC_TEST_SIG` | publish | `HapticTestEvt` | One step of the haptic row. |
| `HAPTIC_FIELD_SIG` | publish | `HapticFieldEvt` | One field's value, or the outcome of writing it. |
| `HAPTIC_DONE_SIG` | publish | `HapticDoneEvt` | A buzz ended. |
| `HAPTIC_PLAY_REQ_SIG` | post | `HapticPlayEvt` | One buzz: `ms` and `gain_pct`. |
| `HAPTIC_FIELD_REQ_SIG` | post | `HapticFieldReqEvt` | Read, write or dump one field of the driver. |
| `HAPTIC_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=haptic`. |
| `HAPTIC_TICK_SIG`, `HAPTIC_TAIL_SIG`, `HAPTIC_WAIT_SIG` | post | `QTimeEvt` | Private timers, in order: feed the RTP FIFO; the chip has played what it was left with; the row's stillness window or the deadline on a reply from AO_Imu. |

### AO_Radio

Published signals: every Active Object that subscribed hears them.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `RADIO_STATE_SIG` | publish | `RadioStateEvt` | The C5 link's state. Published on every change and for each `RADIO_STATE_REQ_SIG`. |
| `WIFI_STATE_SIG` | publish | `WifiStateEvt` | Where the Wi-Fi connection stands. |
| `WIFI_SCAN_ENTRY_SIG` | publish | `WifiScanEntryEvt` | One network found. |
| `WIFI_SCAN_END_SIG` | publish | `WifiScanEndEvt` | The last one: how many, and whether the ceiling cut the scan short. |
| `WIFI_SAVED_ENTRY_SIG` | publish | `WifiSavedEvt` | One remembered network, name only. |
| `WIFI_SAVED_END_SIG` | publish | `WifiScanEndEvt` | The last remembered one, in the same shape. |
| `BLE_STATE_SIG` | publish | `BleStateEvt` | What the BLE half is doing. Published on every change. |
| `BLE_PAIR_SIG` | publish | `BlePairEvt` | A pairing wants a code shown, or has ended. |
| `BLE_SCAN_ENTRY_SIG` | publish | `BleScanEvt` | One device seen. |
| `BLE_SCAN_END_SIG` | publish | `WifiScanEndEvt` | The last one: a count and whether the scan worked. |
| `C5_RUN_REQ_SIG` | publish | bare `QEvt` | Published by whoever needs the C5 running without its link, AO_Audio for the amplifier. |
| `C5_RUNNING_SIG` | publish | bare `QEvt` | The C5 has been out of reset for `KODE_C5_BOOT_MS`: its own boot is over. |

### AO_Radio: posted signals

Posted signals go to one Active Object: requests, replies to the asker, and the private signals and timers.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `RADIO_UP_REQ_SIG` | post | bare `QEvt` | Bring the C5 link up. The outcome is the next `RADIO_STATE_SIG`. |
| `RADIO_DOWN_REQ_SIG` | post | bare `QEvt` | Tear the link down; the C5 keeps running. |
| `RADIO_STATE_REQ_SIG` | post | bare `QEvt` | Publish `RADIO_STATE_SIG` again. |
| `RADIO_JOB_SIG` | post | `KqpWorkerDoneEvt` | Private: a job came back from the radio worker. |
| `RADIO_LINK_LOST_SIG` | post | `RadioLostEvt` | Private: the link to the C5 is gone, from the driver's notification. |
| `RADIO_SVC_JOB_SIG` | post | `KqpWorkerDoneEvt` | Private: a KODE request came back from the service worker. |
| `KODE_SVC_RSP_SIG` | post | `KodeSvcEvt` | Private: a KODE service on the C5 answered. |
| `ID_SIGN_REQ_SIG` | post | `IdSignReqEvt` | Sign the cloud's challenge with the unit's key on the C5. |
| `ID_SIGN_RSP_SIG` | post | `IdSignRspEvt` | To the asker: the signature, or why not. |
| `ID_REQ_SIG` | post | `IdReqEvt` | One identity operation that is not a signature. |
| `ID_PART_SIG` | post | `IdPartEvt` | To the asker: one piece of DER, in order. |
| `ID_END_SIG` | post | `IdEndEvt` | To the asker: the operation is over. |
| `C5_WIPE_REQ_SIG` | post | `C5WipeReqEvt` | Forget the user's secrets: the C5's vault and BLE keys, then the bond store. |
| `C5_WIPE_RSP_SIG` | post | `C5WipeRspEvt` | To the asker: how far the wipe got. |
| `RADIO_SCAN_MORE_SIG` | post | bare `QEvt` | Private: a scan finished a channel and the driver's table grew. |
| `RADIO_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=c5`; brings the link up if it is down. |
| `RADIO_TEST_STEP_SIG` | post | bare `QEvt` | Private: the link is up, take the row's next step. |
| `RADIO_FIELD_REQ_SIG` | post | `RadioFieldReqEvt` | Read, write or dump one field of the coprocessor. |
| `RADIO_FIELD_RSP_SIG` | post | `RadioFieldEvt` | To the requester: the field. |
| `RADIO_RECV_REQ_SIG` | post | `AppRecvReqEvt` | A C5 image is about to arrive on the console. |
| `RADIO_UNUSED_SIG` | post | bare `QEvt` | To itself: its settle found nothing left that uses the link. |
| `RADIO_INSTALL_GO_SIG` | post | bare `QEvt` | Private: the staged image is verified and the link is up, start the push. |
| `RADIO_PARK_REQ_SIG` | post | `RadioParkEvt` | Private, from `radio_park_request()`: a jump is about to restart the board, park the C5. |
| `RADIO_SLEEP_NOTE_SIG` | post | `RadioSleepNoteEvt` | With `CONFIG_KODE_LOWPOWER`, private: the sleep sentinel reports a wake of the P4 that involved the C5 (`kind`, `knocks`, `tx_sta`, `tx_serial`, `tx_hci`). |
| `RADIO_NET_LEFT_SIG` | post | `RadioNetLeftEvt` | With `CONFIG_KODE_LOWPOWER`, from `radio_net_left()`: AO_Net closed its sessions for an OFF round, so the link may go down. |
| `WIFI_SCAN_REQ_SIG` | post | bare `QEvt` | Scan. Entries follow on the bus, then `WIFI_SCAN_END_SIG`. |
| `WIFI_JOIN_REQ_SIG` | post | `WifiJoinEvt` | Join a network and remember it if it works. |
| `WIFI_LEAVE_REQ_SIG` | post | bare `QEvt` | Leave and forget the stored credentials. |
| `WIFI_STATE_REQ_SIG` | post | bare `QEvt` | Publish `WIFI_STATE_SIG` now. |
| `WIFI_RSSI_REQ_SIG` | post | bare `QEvt` | Refresh the association's signal strength; the answer is the next `WIFI_STATE_SIG`. |
| `WIFI_FAST_REQ_SIG` | post | `WifiFastEvt` | No power save on the station (`on`), or the default back. |
| `EXP_POWER_REQ_SIG` | post | `ExpPowerEvt` | Switch J3's `+3.3V_EXT` on or off, from `kode_exp_power()`. |
| `WIFI_AUTO_REQ_SIG` | post | bare `QEvt` | Scan and join the best remembered network in range. |
| `WIFI_LIST_REQ_SIG` | post | bare `QEvt` | Publish the remembered networks, names only. |
| `WIFI_FORGET_REQ_SIG` | post | `WifiJoinEvt` | Remove a network from the store; the password field stays empty. |
| `WIFI_START_REQ_SIG` | post | bare `QEvt` | Enable the Wi-Fi service: set the stored flag, bring the link up, autojoin. |
| `WIFI_STOP_REQ_SIG` | post | bare `QEvt` | Disable it: stop the station and clear the flag. The link stays up. |
| `BLE_START_REQ_SIG` | post | bare `QEvt` | Bring the BLE stack up. Being up is being on the air. |
| `BLE_SCAN_REQ_SIG` | post | `BleScanReqEvt` | Listen for advertisers for the time given. |
| `BLE_STOP_REQ_SIG` | post | bare `QEvt` | Take the BLE stack down. |
| `BLE_STATE_REQ_SIG` | post | bare `QEvt` | Publish `BLE_STATE_SIG` now. |
| `BLE_LINK_SIG` | post | bare `QEvt` | From the driver's callback: a central arrived or left. |
| `BLE_PAIR_TAKE_SIG` | post | bare `QEvt` | To itself, from the driver's callback: collect the pairing record and publish it. |
| `BLE_PAIR_REJECT_REQ_SIG` | post | bare `QEvt` | Refuse the pairing in flight. |
| `BLE_UNPAIR_REQ_SIG` | post | bare `QEvt` | Forget every bonded peer. |
| `RADIO_JOB_GUARD_SIG`, `KODE_SVC_TMO_SIG`, `C5_BOOT_SIG`, `EXP_PULSE_SIG`, `RADIO_RECV_IDLE_SIG`, `RADIO_UNMOUNT_RETRY_SIG` | post | `QTimeEvt` | Private timers, in order: the radio worker's job never came back; a KODE request's answer did not come (one timer per service); the C5 it let go has had its boot time; the C5 reset that switches the header's supply on has lasted; no chunk for `KODE_RECV_IDLE_MS`; the card still answered an unmount as mounted, ask again. |

### AO_Net

Published signals: every Active Object that subscribed hears them.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `NET_PING_ENTRY_SIG` | publish | `NetPingEntryEvt` | One ICMP echo's outcome, a timeout included. |
| `NET_PING_END_SIG` | publish | `NetPingEndEvt` | The session's summary, or the refusal when there was no session. |
| `NET_HTTP_DATA_SIG` | publish | `NetHttpDataEvt` | A slice of a response body. |
| `NET_HTTP_DONE_SIG` | publish | `NetHttpDoneEvt` | Status, lengths, and whether the body was cut. |
| `NET_UDP_DONE_SIG` | publish | `NetUdpDoneEvt` | The datagram is away, or is not. |
| `NET_INFO_SIG` | publish | `NetInfoEvt` | This board's addresses and the MQTT client's state. |
| `MQTT_STATE_SIG` | publish | `MqttStateEvt` | Where the MQTT client is. Published on every change and on request. |
| `MQTT_MSG_SIG` | publish | `MqttMsgEvt` | A message the broker sent. The only published event whose rate a stranger sets. |
| `CHANNEL_STATE_SIG` | publish | `ChannelStateEvt` | Where the Kode channel stands. Published on every change and on request. |

### AO_Net: posted signals

Posted signals go to one Active Object: requests, replies to the asker, and the private signals and timers.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `NET_PING_REQ_SIG` | post | `NetPingReqEvt` | Ping a host. Entries follow on the bus, then `NET_PING_END_SIG`. |
| `NET_HTTP_REQ_SIG` | post | `NetHttpReqEvt` | GET a URL. Body slices follow, then `NET_HTTP_DONE_SIG`. |
| `NET_UDP_REQ_SIG` | post | `NetUdpReqEvt` | Send a datagram. |
| `NET_INFO_REQ_SIG` | post | bare `QEvt` | Publish `NET_INFO_SIG`. |
| `NET_STREAM_OPEN_REQ_SIG` | post | `NetStreamOpenEvt` | Open a download. |
| `NET_STREAM_READ_REQ_SIG` | post | bare `QEvt` | Fill a free buffer and send it. |
| `NET_STREAM_NEXT_SIG` | post | `StorageBufEvt` | A borrowed buffer handed back. |
| `NET_STREAM_CLOSE_REQ_SIG` | post | bare `QEvt` | Close the open transfer. |
| `NET_STREAM_OPEN_RSP_SIG` | post | `StorageOpenRspEvt` | To the opener: the download is open or refused. |
| `NET_STREAM_DATA_SIG` | post | `StorageDataEvt` | To the reader: one buffer of the download. The same conversation AO_Storage has, over a URL. |
| `NET_TEST_REQ_SIG` | post | bare `QEvt` | Run `test component=net`. |
| `NET_JOB_SIG` | post | `KqpWorkerDoneEvt` | Private: a job came back from the worker. |
| `NET_STREAM_JOB_SIG` | post | `KqpWorkerDoneEvt` | Private: a job came back from the download's worker. |
| `MQTT_UP_REQ_SIG` | post | `MqttUpEvt` | Connect to a broker by URI. |
| `MQTT_DOWN_REQ_SIG` | post | bare `QEvt` | Stop the client. |
| `MQTT_PUB_REQ_SIG` | post | `MqttPubEvt` | Publish a message. |
| `MQTT_SUB_REQ_SIG` | post | `MqttTopicEvt` | Subscribe to a topic. |
| `MQTT_UNSUB_REQ_SIG` | post | `MqttTopicEvt` | Unsubscribe from a topic. |
| `MQTT_STATE_REQ_SIG` | post | bare `QEvt` | Publish `MQTT_STATE_SIG` now. |
| `NET_MQTT_LINK_SIG` | post | `NetMqttLinkEvt` | Private: the client connected, dropped or errored, moved off esp-mqtt's task. |
| `NET_MQTT_RX_SIG` | post | static `QEvt` | Private, from esp-mqtt's task: the driver's receive ring holds messages. AO_Net takes them from the ring and republishes each as `MQTT_MSG_SIG` from its own thread. |
| `NET_LINE_DONE_SIG` | post | `NetLineDoneEvt` | From `net_line_done()`: the console answered the line AO_Net gave it from `cmd/in`, so the next may go. Carries the sequence of the line it ends. |
| `NET_LINE_BUSY_SIG` | post | static `QEvt` | From `net_line_busy()`: the console was busy and did not take the line; AO_Net offers it again shortly. |
| `CHANNEL_STATE_REQ_SIG` | post | bare `QEvt` | Publish `CHANNEL_STATE_SIG` now. |
| `NET_CHAN_OUT_SIG` | post | bare `QEvt` | Private: reply lines wait in the channel's ring. Posted by AO_Log. |
| `NET_LEAVE_REQ_SIG` | post | bare `QEvt` | Private, from `net_leave_request()`: leave the Kode channel cleanly and start no new one. |
| `NET_CHECK_AT_SIG` | post | `NetCheckAtEvt` | From `net_check_at()`: the next time the scheduler's `mqtt` entry falls due, in Unix seconds, or -1 for none. |
| `NET_SHOT_REQ_SIG` | post | `NetShotReqEvt` | From `net_shot_request()`: upload the glass to the channel's `shots` link. |
| `NET_SHOT_RSP_SIG` | post | `NetShotRspEvt` | To the requester: how the upload ended. |
| `NET_SHOT_STOP_SIG` | post | `NetShotStopEvt` | From `net_shot_stop_request()`: end the running stream of uploads. |
| `NET_TMO_SIG`, `NET_JOB_GUARD_SIG`, `NET_STREAM_GUARD_SIG`, `NET_CHAN_TMO_SIG`, `NET_CHAN_FAST_SIG`, `NET_CHAN_WATCH_SIG`, `NET_SHOT_TICK_SIG`, `NET_SHOT_WAIT_SIG`, `NET_CHECK_TMO_SIG`, `NET_CHAN_LINE_SIG` | post | `QTimeEvt` | Private timers, in order: the broker never answered the connect; the worker's job never came back; the download's job never came back; the channel's one timer (back-off, renewal); no `cmd/in` line for `CHAN_FAST_HOLD_MS`, the fast mode ends; the channel's client check; the pace of a stream of uploads; the display did not answer a shot; the dwell of a radio wake for the `mqtt` check ran out; the console has had `KODE_CHAN_LINE_BOUND_MS` for the line it holds, or the post of the next line was refused and is tried again. |

### AO_Log

Every signal AO_Log owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `LOG_LINE_SIG` | post | `LogEvt` | Put one log line on the console. |
| `CONSOLE_BYTE_SIG` | post | `ConsoleByteEvt` | A byte arrived. |
| `CONSOLE_RAW_REQ_SIG` | post | `ConsoleRawReqEvt` | Switch the input stream to raw and deliver it to `who`. |
| `CONSOLE_RAW_RSP_SIG` | post | `ConsoleRawRspEvt` | To the requester: whether raw mode is armed. |
| `CONSOLE_RAW_END_SIG` | post | bare `QEvt` | Abandon raw mode: the transfer died before its last byte. |
| `LOG_LEVEL_SET_SIG` | post | `LogLevelEvt` | Apply a log level, and store it when it is the global default. |

### AO_Console

Every signal AO_Console owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `CONSOLE_LINE_SIG` | publish | `ConsoleLineEvt` | A finished command line (`src`, `line[240]`). AO_Log publishes it; AO_Net posts the Kode channel's with a margin. |
| `CONFIG_REQ_SIG` | publish | `KodeConfigReqEvt` | Read or set one setting. The owner answers with `kode_config_answer()`. |
| `CONFIG_ANS_SIG` | publish | `KodeConfigAnsEvt` | A setting's owner: its value, or why it refused. |
| `FUNCTION_ANS_SIG` | post | `FunctionAnsEvt` | Posted by the owner of a function that answers: one record of the answer. |
| `CONSOLE_TIMEOUT_SIG`, `CONSOLE_SLICE_SIG`, `CONSOLE_WATCH_SIG`, `KCLI_INJ_TMO_SIG` | post | `QTimeEvt` | Private timers, in order: the command in flight never got its closing answer; emit the next slice of a listing; a followed variable's period ran out; an injected gesture has a sample due. |

### AO_Gui

Every signal AO_Gui owns.

| Signal | Range | Event | What it does |
| --- | --- | --- | --- |
| `GUI_STATE_SIG` | publish | `GuiStateEvt` | What state the interface is in. AO_Gui lives in kgui, above the SDK. |
| `GUI_DUMP_REQ_SIG` | publish | bare `QEvt` | Say what state the interface is in. The one request in the published range, so kaos need not name a symbol of kgui. |

## In the SDK

- [`kqp_signals.h`](https://github.com/kodediy/kode-sdk/blob/main/components/kqp/include/kqp_signals.h): every signal and every event struct.
- [`components/kqp`](https://github.com/kodediy/kode-sdk/tree/main/components/kqp): the pools, the priorities and the checks.
