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

8.6 KiB
Raw Blame History

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:

FEND <type byte> <data bytes...> FEND

The type byte encodes the port number (upper nibble) and command (lower nibble):

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).

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 CLI or IDE extension.

Build for a specific board:

pio run -e heltec_v3
pio run -e rak_rak4631
pio run -e lilygo_t_beam_1w

Upload to a connected board:

pio run -e heltec_wifi_lora_32_v3 -t upload

Monitor serial output:

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 as the build system with 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.