Initial setup

This commit is contained in:
Maze X
2026-03-27 16:46:56 +01:00
commit 777014f375
4 changed files with 256 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
.cache/

14
.markdownlintrc.json Normal file
View File

@@ -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
}
}

21
.pre-commit-config.yaml Normal file
View File

@@ -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']

219
PROJECT.md Normal file
View File

@@ -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 <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
```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`.