DE

KISS Modem Protocol

KISS Modem Protocol

MeshCore KISS Modem Protocol

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.

Serial Configuration

115200 baud, 8N1, no flow control.

Frame Format

Standard KISS framing per the KA9Q/K3MC specification.

ByteNameDescription
0xC0FENDFrame delimiter
0xDBFESCEscape character
0xDCTFENDEscaped FEND (FESC + TFEND = 0xC0)
0xDDTFESCEscaped FESC (FESC + TFESC = 0xDB)
CLI
┌──────┬───────────┬──────────────┬──────┐
│ FEND │ Type Byte │ Data (escaped)│ FEND │
│ 0xC0 │  1 byte   │ 0-510 bytes  │ 0xC0 │
└──────┴───────────┴──────────────┴──────┘

Type Byte

The type byte is split into two nibbles:

BitsFieldDescription
7–4PortPort number (0 for single-port TNC)
3–0CommandCommand number

Maximum unescaped frame size: 512 bytes.

Standard KISS Commands

Host to TNC

CommandValueDataDescription
Data0x00Raw packetQueue packet for transmission
TXDELAY0x01Delay (1 byte)Transmitter keyup delay in 10 ms units (default: 50 = 500 ms)
Persistence0x02P (1 byte)CSMA persistence parameter 0–255 (default: 63)
SlotTime0x03Interval (1 byte)CSMA slot interval in 10 ms units (default: 10 = 100 ms)
TXtail0x04Delay (1 byte)Post-TX hold time in 10 ms units (default: 0)
FullDuplex0x05Mode (1 byte)0 = half duplex, nonzero = full duplex (default: 0)
SetHardware0x06Sub-command + dataMeshCore extensions (see below)
Return0xFFExit KISS mode (no-op)

TNC to Host

TypeValueDataDescription
Data0x00Raw packetReceived packet from radio

Data frames carry raw packet data only, with no metadata prepended. The Data command payload is limited to 255 bytes to match the MeshCore maximum transmission unit (MAX_TRANS_UNIT); frames larger than 255 bytes are silently dropped. The KISS specification recommends at least 1024 bytes for general-purpose TNCs; this modem is intended for MeshCore packets only, whose protocol MTU is 255 bytes.

CSMA Behavior

The TNC implements p-persistent CSMA for half-duplex operation:

  1. When a packet is queued, monitor carrier detect.
  2. When the channel clears, generate a random value 0–255.
  3. If the value is less than or equal to P (Persistence), wait TXDELAY then transmit.
  4. Otherwise, wait SlotTime and repeat from step 1.
In full-duplex mode, CSMA is bypassed and packets transmit after TXDELAY.

SetHardware Extensions (0x06)

MeshCore-specific functionality uses the standard KISS SetHardware command. The first byte of the SetHardware data is a sub-command. Standard KISS clients ignore these frames.

Frame Format

CLI
┌──────┬──────┬─────────────┬──────────────┬──────┐
│ FEND │ 0x06 │ Sub-command  │ Data (escaped)│ FEND │
│ 0xC0 │      │   1 byte    │   variable   │ 0xC0 │
└──────┴──────┴─────────────┴──────────────┴──────┘

Request Sub-commands (Host to TNC)

Sub-commandValueData
GetIdentity0x01
GetRandom0x02Length (1 byte, 1–64)
VerifySignature0x03PubKey (32) + Signature (64) + Data
SignData0x04Data to sign
EncryptData0x05Key (32) + Plaintext
DecryptData0x06Key (32) + MAC (2) + Ciphertext
KeyExchange0x07Remote PubKey (32)
Hash0x08Data to hash
SetRadio0x09Freq (4) + BW (4) + SF (1) + CR (1)
SetTxPower0x0APower dBm (1)
GetRadio0x0B
GetTxPower0x0C
GetCurrentRssi0x0D
IsChannelBusy0x0E
GetAirtime0x0FPacket length (1)
GetNoiseFloor0x10
GetVersion0x11
GetStats0x12
GetBattery0x13
GetMCUTemp0x14
GetSensors0x15Permissions (1)
GetDeviceName0x16
Ping0x17
Reboot0x18
SetSignalReport0x19Enable (1): 0x00 = disable, nonzero = enable
GetSignalReport0x1A

Response Sub-commands (TNC to Host)

Response codes use the high-bit convention: response = command | 0x80. Generic and unsolicited responses use the 0xF0+ range.

Sub-commandValueData
Identity0x81PubKey (32)
Random0x82Random bytes (1–64)
Verify0x83Result (1): 0x00 = invalid, 0x01 = valid
Signature0x84Signature (64)
Encrypted0x85MAC (2) + Ciphertext
Decrypted0x86Plaintext
SharedSecret0x87Shared secret (32)
Hash0x88SHA-256 hash (32)
Radio0x8BFreq (4) + BW (4) + SF (1) + CR (1)
TxPower0x8CPower dBm (1)
CurrentRssi0x8DRSSI dBm (1, signed)
ChannelBusy0x8EResult (1): 0x00 = clear, 0x01 = busy
Airtime0x8FMilliseconds (4)
NoiseFloor0x90dBm (2, signed)
Version0x91Version (1) + Reserved (1)
Stats0x92RX (4) + TX (4) + Errors (4)
Battery0x93Millivolts (2)
MCUTemp0x94Temperature (2, signed)
Sensors0x95CayenneLPP payload
DeviceName0x96Name (variable, UTF-8)
Pong0x97
SignalReport0x9AStatus (1): 0x00 = disabled, 0x01 = enabled
OK0xF0
Error0xF1Error code (1)
TxDone0xF8Result (1): 0x00 = failed, 0x01 = success
RxMeta0xF9SNR (1) + RSSI (1)

Error Codes

CodeValueDescription
InvalidLength0x01Request data too short
InvalidParam0x02Invalid parameter value
NoCallback0x03Feature not available
MacFailed0x04MAC verification failed
UnknownCmd0x05Unknown sub-command
EncryptFailed0x06Encryption failed
TxBusy0x07Transmit busy

Unsolicited Events

The TNC sends these SetHardware frames without a preceding request:

TxDone (0xF8): Sent after a packet has been transmitted. Contains a single byte: 0x01 for success, 0x00 for failure. RxMeta (0xF9): Sent immediately after each standard data frame (type 0x00) with metadata for the received packet. Contains SNR (1 byte, signed, value ×4 for 0.25 dB precision) followed by RSSI (1 byte, signed, dBm). Enabled by default; can be toggled with SetSignalReport. Standard KISS clients ignore this frame.

Data Formats

Radio Parameters (SetRadio / Radio Response)

All values little-endian.

FieldSizeDescription
Frequency4 bytesHz (e.g., 869618000)
Bandwidth4 bytesHz (e.g., 62500)
SF1 byteSpreading factor (5–12)
CR1 byteCoding rate (5–8)

Version (Version Response)

FieldSizeDescription
Version1 byteFirmware version
Reserved1 byteAlways 0

Encrypted (Encrypted Response)

FieldSizeDescription
MAC2 bytesHMAC-SHA256 truncated to 2 bytes
CiphertextvariableAES-128 block-encrypted data with zero padding

Airtime (Airtime Response)

All values little-endian.

FieldSizeDescription
Airtime4 bytesuint32_t, estimated air time in milliseconds

Noise Floor (NoiseFloor Response)

All values little-endian.

FieldSizeDescription
Noise floor2 bytesint16_t, dBm (signed)

The modem recalibrates the noise floor every 2 seconds with an AGC reset every 30 seconds.

Stats (Stats Response)

All values little-endian.

FieldSizeDescription
RX4 bytesPackets received
TX4 bytesPackets transmitted
Errors4 bytesReceive errors

Battery (Battery Response)

All values little-endian.

FieldSizeDescription
Millivolts2 bytesuint16_t, battery voltage in mV

MCU Temperature (MCUTemp Response)

All values little-endian.

FieldSizeDescription
Temperature2 bytesint16_t, tenths of °C (e.g., 253 = 25.3 °C)

Returns NoCallback error if the board does not support temperature readings.

Device Name (DeviceName Response)

FieldSizeDescription
NamevariableUTF-8 string, no null terminator

Reboot

Sends an OK response, flushes serial, then reboots the device. The host should expect the connection to drop.

Sensor Permissions (GetSensors)

BitValueDescription
00x01Base (battery)
10x02Location (GPS)
20x04Environment (temp, humidity, pressure)

Use 0x07 for all permissions.

Sensor Data (Sensors Response)

Data returned in CayenneLPP format. See CayenneLPP documentation for parsing.

Cryptographic Algorithms

OperationAlgorithm
Identity / Signing / VerificationEd25519
Key ExchangeX25519 (ECDH)
EncryptionAES-128 block encryption with zero padding + HMAC-SHA256 (MAC truncated to 2 bytes)
HashingSHA-256

Notes

  • Data payload limit (255 bytes) matches MeshCore MAX_TRANS_UNIT; no change is needed for the KISS "1024+ recommended" guideline (that applies to general TNCs, not MeshCore).
  • The modem generates its identity on first boot (stored in flash).
  • All multi-byte values are little-endian unless stated otherwise.
  • SNR values in RxMeta are multiplied by 4 for 0.25 dB precision.
  • TxDone is sent as a SetHardware event after each transmission.
  • Standard KISS clients receive only type 0x00 data frames and can safely ignore all SetHardware (0x06) frames.
  • See packet_format.md for packet format.

Source: docs.meshcore.io