# 10.RadioGateway - bridge a southbound radio to the northbound stack

**Layer:** Foundation · **Build flags:** `DETWS_ENABLE_DMA`,
`DETWS_ENABLE_PREEMPT_QUEUE`, `DETWS_ENABLE_GATEWAY`, `DETWS_DMA_SIMULATE`

## What this example teaches

The capstone of the v5 ingest pipeline: a **wireless gateway**. A southbound radio
(LoRa / nRF24 / Zigbee / ... reached over SPI / I2C / UART) receives frames, and the
device **bridges** them to the web stack - MQTT / HTTP / WebSocket.

```
radio RX --DMA--> callback --post--> FORWARD lane --> codec --> det_gw_uplink()
                                                                     |
                                            envelope + topic  lora/<port>/<addr>
                                                                     |
                                                     northbound publish (MQTT/HTTP/WS)
```

Everything below the codec is a feature from earlier examples:

- **[DMA](../07.DmaIngest/README.md)** reads the radio's bytes into a static buffer and
  fires a completion.
- The **[FORWARD lane](../08.PreemptLanes/README.md)** carries the frame off the
  interrupt to a task.
- A tiny **per-radio codec** (here: the first two bytes are the source node address, the
  rest is payload) turns raw bytes into an addressed frame.
- The **gateway** (`services/gateway`) envelopes and publishes it.

## The gateway

Register each radio as a **port** (with an optional transmit callback for downlink), and
install the **uplink** - the northbound publish:

```cpp
det_gw_port_config p = {};
p.port_id = 0; p.kind = DET_GW_LORA; p.tx = radio_tx; // tx = the radio's send()
det_gw_add_port(&p);
det_gw_set_uplink(northbound_publish, nullptr);       // e.g. mqtt.publish(...)
det_gw_set_topic_prefix("lora");

// a frame arrived from node 0x42 on port 0:
det_gw_uplink(0, 0x42, payload, len, rssi);           // -> publishes lora/0/66
```

- **Envelope**: each uplink builds a `det_gw_msg` with the source address, port, RSSI,
  and a sequence number. `det_gw_topic()` formats a routing key `<prefix>/<port>/<addr>`.
- **Downlink**: `det_gw_downlink(port, dst_addr, payload, len)` transmits a northbound
  command back out the radio via the port's transmit callback.
- **Rate cap**: a per-port `rate_cap` (frames/second) throttles a chatty radio; excess is
  dropped, not blocked.
- **Fail-closed**: no installed sink, an unknown port, an exceeded cap, or a callback
  refusing drops the frame and is counted (`det_gw_get_stats()`), never blocks.

The radio TX and the northbound publish are **callbacks**, so this runs with no radio
hardware: the sketch feeds simulated frames through the DMA simulator and prints the
publishes. A real build swaps the feed for the module's SPI RX and the publish for an
MQTT client - the pipeline is unchanged.

Storage is static (zero heap): `DETWS_GW_MAX_PORTS` ports.

## Build-flag note

The flags must reach the library build, so pass them as build flags:

```sh
pio ci --board=esp32dev --project-option="framework=arduino" \
  --project-option="build_flags=-DDETWS_ENABLE_DMA=1 -DDETWS_ENABLE_PREEMPT_QUEUE=1 -DDETWS_ENABLE_GATEWAY=1 -DDETWS_DMA_SIMULATE=1" \
  --lib="." examples/Foundation/10.RadioGateway/10.RadioGateway.ino
```
