Files
lorakiss/PROJECT.md
Maze X 8883ee3e94 Scaffold PlatformIO project with 20 board configs and C99/C++ source skeleton
Three-tier configuration hierarchy:
- [env:base] — RadioLib + default LoRa parameters
- [soc_esp32/esp32s3/nrf52] — platform + framework per SoC
- [env:board_name] — board-specific pins + chip selection

20 boards across 4 vendors:
- Heltec: 11 boards (T114, CT62, E213, E290, Mesh Solar, T190, Tracker,
  Tracker V2, V2, V3, V4)
- LilyGo: 4 boards (T-Beam 1W, sx1262, sx1276, supreme)
- Seeed: 1 board (Xiao S3 + Wio SX1262 with verified pins)
- RAK: 4 boards (RAK11310, RAK3112, RAK3401, RAK3x72, RAK4631)

Known/verified pins: Heltec V2/V3/V4, RAK4631, Seeed Xiao S3
FIXME pins: all others (placeholders for future research)

Source skeleton:
- config.h — compile-time defaults + pin validation (#error checks)
- kiss.h/c — KISS protocol implementation (C99)
- radio.h/cpp — RadioLib wrapper with C API (extern "C" boundary)
- main.cpp — Arduino entry point

All files pass pre-commit (prettier, markdownlint, YAML check).
2026-03-27 17:15:30 +01:00

226 lines
8.6 KiB
Markdown
Raw Permalink 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.
# Micro controller LoRa KISS modem
This project is a LoRa KISS modem for common LoRa capable development boards,
such as created by vendors like Heltec, RAK, Seeed, etc.
It is using the USB-serial interface (optionally hardware serial interface) to
allow the user to send and receive LoRa packets using the KISS modem protocol.
## KISS Modem
### KISS Framing
KISS (Keep It Simple, Stupid) is a standard TNC protocol for packet radio.
Frames use special bytes for delimiting:
| Symbol | Value | Meaning |
| ------ | ------ | ------------------------------ |
| FEND | `0xC0` | Frame end/begin delimiter |
| FESC | `0xDB` | Frame escape |
| TFEND | `0xDC` | Transposed FEND (follows FESC) |
| TFESC | `0xDD` | Transposed FESC (follows FESC) |
A frame has the structure:
```text
FEND <type byte> <data bytes...> FEND
```
The type byte encodes the port number (upper nibble) and command (lower
nibble):
```text
type = (port << 4) | cmd
```
For host-to-modem data frames, `cmd = 0x00`. Any `FEND` or `FESC` bytes
appearing in the data payload must be escaped as `FESC TFEND` or `FESC TFESC`
respectively.
### Ports
The KISS modem uses three ports for communication:
| Port | Direction | Purpose |
| ---- | ------------- | ---------------------------- |
| 0 | bidirectional | Raw LoRa packet data |
| 1 | TNC → host | Signal quality (SNR + RSSI) |
| 2 | bidirectional | Radio configuration commands |
### Port 1 — Signal Quality
Before each received LoRa packet delivered on port 0, the modem emits a signal
quality frame on port 1. The payload is 3 bytes, big-endian:
| Offset | Size | Type | Field | Description |
| ------ | ---- | ----- | ----- | ------------------------------------- |
| 0 | 1 | int8 | SNR | Signal-to-noise ratio in dB (rounded) |
| 1 | 2 | int16 | RSSI | Received signal strength in dBm |
Example: `FEND 0x11 [-7] [0xFF 0x99] FEND` = SNR = -7 dB, RSSI = -103 dBm
### Configuration Commands (Port 2)
Configuration commands allow the host to query and control the modem's LoRa
parameters. Each configuration frame's data payload (after the KISS type byte)
begins with a 1-byte command byte. The modem responds to every SET\_\* command
with either RES_OK (`0x01`) or RES_ERROR (`0x02`) on port 2.
**Commands:**
| Cmd | Name | Dir | Payload |
| ---- | ------------- | --- | ------------------------------ |
| 0x00 | Reserved | — | — |
| 0x01 | RES_OK | ← | (none) |
| 0x02 | RES_ERROR | ← | (none) |
| 0x10 | GET_RADIO | → | (none) |
| 0x10 | _resp_ | ← | freq_kHz, bw_hz, sf, cr, power |
| 0x11 | SET_RADIO | → | freq_kHz, bw_hz, sf, cr, power |
| 0x12 | GET_FREQUENCY | → | (none) |
| 0x12 | _resp_ | ← | freq_kHz |
| 0x13 | SET_FREQUENCY | → | freq_kHz |
| 0x14 | GET_BANDWIDTH | → | (none) |
| 0x14 | _resp_ | ← | bw_hz |
| 0x15 | SET_BANDWIDTH | → | bw_hz |
| 0x16 | GET_SF | → | (none) |
| 0x16 | _resp_ | ← | sf |
| 0x17 | SET_SF | → | sf |
| 0x18 | GET_CR | → | (none) |
| 0x18 | _resp_ | ← | cr |
| 0x19 | SET_CR | → | cr |
| 0x1A | GET_POWER | → | (none) |
| 0x1A | _resp_ | ← | power_dBm |
| 0x1B | SET_POWER | → | power_dBm |
| 0x1C | GET_SYNCWORD | → | (none) |
| 0x1C | _resp_ | ← | syncword |
| 0x1D | SET_SYNCWORD | → | syncword |
Legend: `→` = host → TNC, `←` = TNC → host
### Units
All integer fields are transmitted in big-endian byte order.
| Parameter | Type | Unit | Encoding | Example |
| --------- | ------ | ---- | ------------- | -------------------- |
| Frequency | uint32 | kHz | 4 bytes | 869.618 MHz → 869618 |
| Bandwidth | uint32 | Hz | 4 bytes | 62.5 kHz → 62500 |
| SF | uint8 | — | 1 byte (512) | SF 7 → 0x07 |
| CR | uint8 | — | 1 byte (58) | 4/5 → 0x05 |
| Power | int8 | dBm | 1 byte | 22 dBm → 0x16 |
| Sync word | uint8 | — | 1 byte | 0x34 → public |
## LoRa
### Hardware
Common LoRa hardware is supported via the RadioLib library:
| Module | Frequency band | Notes |
| --------------- | -------------------- | ------------------------------------ |
| SX1262 | 868 / 915 MHz | Used on Heltec, RAK, Seeed boards |
| SX1268 | 433 / 470 MHz | 433 MHz ISM band variants |
| LR1110 | 150960 MHz | Semtech LR11xx family |
| LR1120 | 150960 MHz, 2.4 GHz | Semtech LR11xx family |
| SX1276 / SX1278 | 1371020 MHz | Older boards; supported via RadioLib |
### Bandwidths
All LoRa bandwidths supported by RadioLib are accepted. SX126x-based boards support:
| Bandwidth | Wire value (uint32 Hz) |
| --------- | ---------------------- |
| 7.8 kHz | 7800 |
| 10.4 kHz | 10400 |
| 15.6 kHz | 15600 |
| 20.8 kHz | 20800 |
| 31.25 kHz | 31250 |
| 41.7 kHz | 41700 |
| 62.5 kHz | 62500 |
| 125 kHz | 125000 |
| 250 kHz | 250000 |
| 500 kHz | 500000 |
Note: SX1272/SX1273-based boards support only 125, 250, and 500 kHz.
Not all bandwidths are legal for all frequency bands — consult local regulations.
## Project Structure
Three-tier configuration hierarchy: base + SoC + board. Pin definitions are compile-time
macros in board configs (no separate pins.h).
```text
loramodem/
├── platformio.ini # [platformio] + [env:base]
├── soc/ # SoC shared configs
│ ├── esp32/platformio.ini
│ ├── esp32s3/platformio.ini
│ └── nrf52/platformio.ini
├── hardware/ # 20 board configs
│ ├── heltec/ (11 boards)
│ ├── lilygo/ (4 boards)
│ ├── seeed/ (1 board)
│ └── rak/ (4 boards)
└── src/
├── main.cpp # Arduino setup()/loop() — calls C APIs
├── kiss.h / kiss.c # KISS protocol — C99
├── radio.h / radio.cpp # RadioLib wrapper — C++ (extern "C" API)
└── config.h # Compile-time defaults + pin validation
```
## Building
Prerequisites: [PlatformIO](https://platformio.org/) CLI or IDE extension.
**Build for a specific board:**
```sh
pio run -e heltec_v3
pio run -e rak_rak4631
pio run -e lilygo_t_beam_1w
```
**Upload to a connected board:**
```sh
pio run -e heltec_wifi_lora_32_v3 -t upload
```
**Monitor serial output:**
```sh
pio device monitor -b 115200
```
Note: KISS frames are binary. Use a KISS-capable TNC client (e.g., Direwolf,
socat) to interact with the modem over serial.
Available board environments are defined in `platformio.ini`.
## Configuration Defaults
The modem initializes with these LoRa parameters at power-on:
| Parameter | Default value |
| --------- | -------------------- |
| Frequency | TBD MHz |
| Bandwidth | 125 kHz |
| SF | TBD |
| CR | 4/5 |
| Power | TBD dBm |
| Sync word | `0x34` (LoRa public) |
These defaults may be overridden at compile time via `config.h`. Parameters changed
via KISS port 2 commands take effect immediately but are **not persisted** across
power cycles unless persistent storage (EEPROM/NVS) is implemented.
## Framework
This project uses [PlatformIO](https://platformio.org/) as the build system with
[RadioLib](https://github.com/jgromes/RadioLib) as the LoRa driver library.
Board-specific pin assignments and hardware configurations are isolated in the
`variants/` directory, allowing the core KISS modem logic to remain board-agnostic.
The USB-CDC serial interface is used by default for KISS communication. On supported
boards, a hardware UART may be selected instead via compile-time configuration in `config.h`.