Files
lorakiss/PROJECT.md
2026-03-27 16:46:56 +01:00

8.5 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

loramodem/
├── platformio.ini          # Board environments and build configuration
├── PROJECT.md              # This file
├── src/
│   ├── main.cpp            # Entry point; Arduino setup() and loop()
│   ├── kiss.h / kiss.cpp   # KISS frame encoder/decoder
│   ├── radio.h / radio.cpp # RadioLib wrapper (init, TX, RX, config)
│   └── config.h            # Default radio parameters and pin definitions
├── include/                # Shared headers (if needed)
├── lib/                    # Local libraries (if needed)
├── variants/               # Board-specific hardware definitions
│   ├── heltec_wifi_lora_32_v3/pins.h
│   ├── rak4631/pins.h
│   └── [other boards]/pins.h
└── test/                   # PlatformIO Unity test suite

Building

Prerequisites: PlatformIO CLI or IDE extension.

Build for a specific board:

pio run -e heltec_wifi_lora_32_v3

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.