commit 777014f375d020fa07c0891799c747da4f33fdfb Author: Maze X Date: Fri Mar 27 16:46:56 2026 +0100 Initial setup diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbf0615 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +.cache/ diff --git a/.markdownlintrc.json b/.markdownlintrc.json new file mode 100644 index 0000000..33f74e2 --- /dev/null +++ b/.markdownlintrc.json @@ -0,0 +1,14 @@ +{ + "extends": "default", + "rules": { + "line-length": { + "line_length": 120, + "heading_line_length": 120, + "code_blocks": false, + "code_lines": false, + "tables": false + }, + "fenced-code-language": false, + "no-trailing-spaces": true + } +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e7a30cf --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + args: ['--maxkb=1000'] + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier + types_or: [markdown] + + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.37.0 + hooks: + - id: markdownlint + args: ['--fix', '--disable', 'MD040', '--disable', 'MD013'] diff --git a/PROJECT.md b/PROJECT.md new file mode 100644 index 0000000..3960c3b --- /dev/null +++ b/PROJECT.md @@ -0,0 +1,219 @@ +# 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 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 (5–12) | SF 7 → 0x07 | +| CR | uint8 | — | 1 byte (5–8) | 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 | 150–960 MHz | Semtech LR11xx family | +| LR1120 | 150–960 MHz, 2.4 GHz | Semtech LR11xx family | +| SX1276 / SX1278 | 137–1020 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 + +```text +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](https://platformio.org/) CLI or IDE extension. + +**Build for a specific board:** + +```sh +pio run -e heltec_wifi_lora_32_v3 +``` + +**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`.