Standard KISS TNC firmware for MeshCore LoRa radios. Compatible with any KISS client (Direwolf, APRSdroid, YAAC, etc.) for sending and receiving raw packets. MeshCore-specific extensions (cryptography, radio configuration, telemetry) are available through the standard SetHardware (0x06) command.
115200 baud, 8N1, no flow control.
Standard KISS framing per the KA9Q/K3MC specification.
| Byte | Name | Description |
|---|---|---|
0xC0 |
FEND | Frame delimiter |
0xDB |
FESC | Escape character |
0xDC |
TFEND | Escaped FEND (FESC + TFEND = 0xC0) |
0xDD |
TFESC | Escaped FESC (FESC + TFESC = 0xDB) |
┌──────┬───────────┬──────────────┬──────┐
│ FEND │ Type Byte │ Data (escaped)│ FEND │
│ 0xC0 │ 1 byte │ 0-510 bytes │ 0xC0 │
└──────┴───────────┴──────────────┴──────┘
The type byte is split into two nibbles:
| Bits | Field | Description |
|---|---|---|
| 7-4 | Port | Port number (0 for single-port TNC) |
| 3-0 | Command | Command number |
Maximum unescaped frame size: 512 bytes.
| Command | Value | Data | Description |
|---|---|---|---|
| Data | 0x00 |
Raw packet | Queue packet for transmission |
| TXDELAY | 0x01 |
Delay (1 byte) | Transmitter keyup delay in 10ms units (default: 50 = 500ms) |
| Persistence | 0x02 |
P (1 byte) | CSMA persistence parameter 0-255 (default: 63) |
| SlotTime | 0x03 |
Interval (1 byte) | CSMA slot interval in 10ms units (default: 10 = 100ms) |
| TXtail | 0x04 |
Delay (1 byte) | Post-TX hold time in 10ms units (default: 0) |
| FullDuplex | 0x05 |
Mode (1 byte) | 0 = half duplex, nonzero = full duplex (default: 0) |
| SetHardware | 0x06 |
Sub-command + data | MeshCore extensions (see below) |
| Return | 0xFF |
- | Exit KISS mode (no-op) |
| Type | Value | Data | Description |
|---|---|---|---|
| Data | 0x00 |
Raw packet | Received packet from radio |
Data frames carry raw packet data only, with no metadata prepended.
The TNC implements p-persistent CSMA for half-duplex operation:
In full-duplex mode, CSMA is bypassed and packets transmit after TXDELAY.
MeshCore-specific functionality uses the standard KISS SetHardware command. The first byte of SetHardware data is a sub-command. Standard KISS clients ignore these frames.
┌──────┬──────┬─────────────┬──────────────┬──────┐
│ FEND │ 0x06 │ Sub-command │ Data (escaped)│ FEND │
│ 0xC0 │ │ 1 byte │ variable │ 0xC0 │
└──────┴──────┴─────────────┴──────────────┴──────┘
| Sub-command | Value | Data |
|---|---|---|
| GetIdentity | 0x01 |
- |
| GetRandom | 0x02 |
Length (1 byte, 1-64) |
| VerifySignature | 0x03 |
PubKey (32) + Signature (64) + Data |
| SignData | 0x04 |
Data to sign |
| EncryptData | 0x05 |
Key (32) + Plaintext |
| DecryptData | 0x06 |
Key (32) + MAC (2) + Ciphertext |
| KeyExchange | 0x07 |
Remote PubKey (32) |
| Hash | 0x08 |
Data to hash |
| SetRadio | 0x09 |
Freq (4) + BW (4) + SF (1) + CR (1) |
| SetTxPower | 0x0A |
Power dBm (1) |
| GetRadio | 0x0C |
- |
| GetTxPower | 0x0D |
- |
| GetVersion | 0x0F |
- |
| GetCurrentRssi | 0x10 |
- |
| IsChannelBusy | 0x11 |
- |
| GetAirtime | 0x12 |
Packet length (1) |
| GetNoiseFloor | 0x13 |
- |
| GetStats | 0x14 |
- |
| GetBattery | 0x15 |
- |
| Ping | 0x16 |
- |
| GetSensors | 0x17 |
Permissions (1) |
| Sub-command | Value | Data |
|---|---|---|
| Identity | 0x21 |
PubKey (32) |
| Random | 0x22 |
Random bytes (1-64) |
| Verify | 0x23 |
Result (1): 0x00=invalid, 0x01=valid |
| Signature | 0x24 |
Signature (64) |
| Encrypted | 0x25 |
MAC (2) + Ciphertext |
| Decrypted | 0x26 |
Plaintext |
| SharedSecret | 0x27 |
Shared secret (32) |
| Hash | 0x28 |
SHA-256 hash (32) |
| OK | 0x29 |
- |
| Radio | 0x2A |
Freq (4) + BW (4) + SF (1) + CR (1) |
| TxPower | 0x2B |
Power dBm (1) |
| Version | 0x2D |
Version (1) + Reserved (1) |
| Error | 0x2E |
Error code (1) |
| TxDone | 0x2F |
Result (1): 0x00=failed, 0x01=success |
| CurrentRssi | 0x30 |
RSSI dBm (1, signed) |
| ChannelBusy | 0x31 |
Result (1): 0x00=clear, 0x01=busy |
| Airtime | 0x32 |
Milliseconds (4) |
| NoiseFloor | 0x33 |
dBm (2, signed) |
| Stats | 0x34 |
RX (4) + TX (4) + Errors (4) |
| Battery | 0x35 |
Millivolts (2) |
| Pong | 0x36 |
- |
| Sensors | 0x37 |
CayenneLPP payload |
| RxMeta | 0x38 |
SNR (1) + RSSI (1) |
| Code | Value | Description |
|---|---|---|
| InvalidLength | 0x01 |
Request data too short |
| InvalidParam | 0x02 |
Invalid parameter value |
| NoCallback | 0x03 |
Feature not available |
| MacFailed | 0x04 |
MAC verification failed |
| UnknownCmd | 0x05 |
Unknown sub-command |
| EncryptFailed | 0x06 |
Encryption failed |
The TNC sends these SetHardware frames without a preceding request:
TxDone (0x2F): Sent after a packet has been transmitted. Contains a single byte: 0x01 for success, 0x00 for failure.
RxMeta (0x38): Sent immediately after each standard data frame (type 0x00) with metadata for the received packet. Contains SNR (1 byte, signed, value x4 for 0.25 dB precision) followed by RSSI (1 byte, signed, dBm). Standard KISS clients ignore this frame.
All values little-endian.
| Field | Size | Description |
|---|---|---|
| Frequency | 4 bytes | Hz (e.g., 869618000) |
| Bandwidth | 4 bytes | Hz (e.g., 62500) |
| SF | 1 byte | Spreading factor (5-12) |
| CR | 1 byte | Coding rate (5-8) |
All values little-endian.
| Field | Size | Description |
|---|---|---|
| RX | 4 bytes | Packets received |
| TX | 4 bytes | Packets transmitted |
| Errors | 4 bytes | Receive errors |
| Bit | Value | Description |
|---|---|---|
| 0 | 0x01 |
Base (battery) |
| 1 | 0x02 |
Location (GPS) |
| 2 | 0x04 |
Environment (temp, humidity, pressure) |
Use 0x07 for all permissions.
Data returned in CayenneLPP format. See CayenneLPP documentation for parsing.