M17 Protocol Specification

M17 RF Protocol: Summary

M17 is an RF protocol that is:

  • Completely open: open specification, open source code, open source hardware, open algorithms. Anyone must be able to build an M17 radio and interoperate with other M17 radios without having to pay anyone else for the right to do so.
  • Optimized for amateur radio use.
  • Simple to understand and implement.
  • Capable of doing the things hams expect their digital protocols to do:
    • Voice (eg: DMR, D-Star, etc)
    • Point to point data (eg: Packet, D-Star, etc)
    • Broadcast telemetry (eg: APRS, etc)
    • Extensible, so more capabilities can be added over time.

To do this, the M17 protocol is broken down into three protocol layers, like a network:

  1. Physical Layer: How to encode 1s and 0s into RF. Specifies RF modulation, symbol rates, bits per symbol, etc.
  2. Data Link Layer: How to packetize those 1s and 0s into usable data. Packet vs Stream modes, headers, addressing, etc.
  3. Application Layer: Accomplishing activities. Voice and data streams, control packets, beacons, etc.

This document attempts to document these layers.

[TETRA]Dunlop, John; Girma, Demessie; Irvine, James “Digital Mobile Communications and the TETRA System” Wiley 1999, ISBN: 9780471987925
[DMR]ETSI TS 102 361-1 V2.2.1 (2013-02): “Electromagnetic compatibility and Radio spectrum Matters (ERM); Digital Mobile Radio (DMR) Systems; Part 1: DMR Air Interface (AI) protocol” https://www.etsi.org/deliver/etsi_ts/102300_102399/10236101/02.02.01_60/ts_10236101v020201p.pdf

Glossary

ECC
Error Correcting Code
FEC
Forward Error Correction
Frame
The individual components of a stream, each of which contains payload data interleaved with frame signalling.
The first frame of any transmission. It contains full LICH data.
LICH
Link Information Channel. The LICH contains all information needed to establish an M17 link. The first frame of a transmission contains full LICH data, and subsequent frames each contain one sixth of the LICH data so that late-joiners can obtain the LICH.
Packet
A single burst of transmitted data containing 100s to 1000s of bytes, after which the physical layer stops sending data.
Superframe
A set of six consecutive frames which collectively contain full LICH data are grouped into a superframe.

Physical Layer

4FSK generation

M17 standard uses 4FSK modulation running at 4800 symbols/s (9600 bits/s) with a deviation index h=0.33 for transmission in 9 kHz channel bandwidth. Channel spacing is 12.5 kHz. The symbol stream is converted to a series of impulses which pass through a root-raised-cosine (alpha=0.5) shaping filter before frequency modulation at the transmitter and again after frequency demodulation at the receiver.

RRC filter and Frequency Modulation

4FSK modulator dataflow

The bit-to-symbol mapping is shown in the table below.

Dibit symbol mapping to 4FSK deviation
Information bits Symbol 4FSK deviation
Bit 1 Bit 0
0 1 +3 +2.4 kHz
0 0 +1 +0.8 kHz
1 0 -1 -0.8 kHz
1 1 -3 -2.4 kHz

The most significant bits are sent first, meaning that the byte 0xB4 (= 0b10’11’01’00) in type 4 bits (see Bit types) would be sent as the symbols -1 -3 +3 +1. All data fields utilize big-endian order of bytes unless specified otherwise.

Preamble

Every transmission starts with a preamble, which shall consist of at least 40 ms of alternating -3, +3… symbols. This is equivalent to 40 milliseconds of a 2400 Hz tone

Bit types

The bits at different stages of the error correction coding are referred to with bit types, given in Table 2.

Bit types
Type 1 Data link layer bits
Type 2 Bits after appropriate encoding
Type 3 Bits after puncturing (only for convolutionally coded data, for other ECC schemes type 3 bits are the same as type 2 bits)
Type 4 Decorrelated and interleaved (re-ordered) type 3 bits

Type 4 bits are used for transmission over the RF. Incoming type 4 bits shall be decoded to type 1 bits, which are then used to extract all the frame fields.

Error correction coding schemes and bit type conversion

Two distinct ECC/FEC schemes are used for different parts of the transmission.

Subsequent frames

_images/frame_encoding.svg

ECC stages of subsequent frames

A 40-bit (type 1) chunk of the LSF along with a 3-bit modulo 6 counter (LICH_CNT) and 5 reserved bits (see Table 7) is partitioned into 4 12-bit parts and encoded using Golay (24, 12) code. This produces 96 encoded bits of type 2. These bits are used in the Link Information Channel (LICH).

16-bit FN and 128 bits of payload (144 bits total) are convolutionally encoded in a manner analogous to that of the link setup frame. A total of 148 bits is being encoded resulting in 296 type 2 bits. These bits are punctured to generate 272 type 3 bits.

96 type 2 bits of LICH are concatenated with 272 type 3 bits and re-ordered to form type 4 bits for transmission. This, along with 16-bit sync in the beginning of frame, gives a total of 384 bits

The LICH chunks allow for late listening and indepedent decoding to check destination address. The goal is to require less complexity to decode just the LICH and check if the full message should be decoded.

Packet Frames

_images/packet_frame_encoding.svg

Packet frame encoding

Extended Golay(24,12) code

The extended Golay(24,12) encoder uses generating polynomial g given below to generate the 11 check bits. The check bits and an additional parity bit are appended to the 12 bit data, resulting in a 24 bit codeword. The resulting code is systematic, meaning that the input data (message) is embedded in the codeword.

\[\begin{align} g(x) = x^{11} + x^{10} + x^6 + x^5 + x^4 + x^2 + 1 \end{align}\]

This is equivalent to 0xC75 in hexadecimal notation. Both the generating matrix G and parity check matrix H are shown below.

\begin{align} G = \begin{bmatrix} I_k | P \end{bmatrix} = & \begin{bmatrix} 1&0&0&0&0&0&0&0&0&0&0&0&1&1&0&0&0&1&1&1&0&1&0&1\\ 0&1&0&0&0&0&0&0&0&0&0&0&0&1&1&0&0&0&1&1&1&0&1&1\\ 0&0&1&0&0&0&0&0&0&0&0&0&1&1&1&1&0&1&1&0&1&0&0&0\\ 0&0&0&1&0&0&0&0&0&0&0&0&0&1&1&1&1&0&1&1&0&1&0&0\\ 0&0&0&0&1&0&0&0&0&0&0&0&0&0&1&1&1&1&0&1&1&0&1&0\\ 0&0&0&0&0&1&0&0&0&0&0&0&1&1&0&1&1&0&0&1&1&0&0&1\\ 0&0&0&0&0&0&1&0&0&0&0&0&0&1&1&0&1&1&0&0&1&1&0&1\\ 0&0&0&0&0&0&0&1&0&0&0&0&0&0&1&1&0&1&1&0&0&1&1&1\\ 0&0&0&0&0&0&0&0&1&0&0&0&1&1&0&1&1&1&0&0&0&1&1&0\\ 0&0&0&0&0&0&0&0&0&1&0&0&1&0&1&0&1&0&0&1&0&1&1&1\\ 0&0&0&0&0&0&0&0&0&0&1&0&1&0&0&1&0&0&1&1&1&1&1&0\\ 0&0&0&0&0&0&0&0&0&0&0&1&1&0&0&0&1&1&1&0&1&0&1&1\\ \end{bmatrix} \newline\newline H = \begin{bmatrix} P^T | I_k \end{bmatrix} = & \begin{bmatrix} 1&0&1&0&0&1&0&0&1&1&1&1&1&0&0&0&0&0&0&0&0&0&0&0\\ 1&1&1&1&0&1&1&0&1&0&0&0&0&1&0&0&0&0&0&0&0&0&0&0\\ 0&1&1&1&1&0&1&1&0&1&0&0&0&0&1&0&0&0&0&0&0&0&0&0\\ 0&0&1&1&1&1&0&1&1&0&1&0&0&0&0&1&0&0&0&0&0&0&0&0\\ 0&0&0&1&1&1&1&0&1&1&0&1&0&0&0&0&1&0&0&0&0&0&0&0\\ 1&0&1&0&1&0&1&1&1&0&0&1&0&0&0&0&0&1&0&0&0&0&0&0\\ 1&1&1&1&0&0&0&1&0&0&1&1&0&0&0&0&0&0&1&0&0&0&0&0\\ 1&1&0&1&1&1&0&0&0&1&1&0&0&0&0&0&0&0&0&1&0&0&0&0\\ 0&1&1&0&1&1&1&0&0&0&1&1&0&0&0&0&0&0&0&0&1&0&0&0\\ 1&0&0&1&0&0&1&1&1&1&1&0&0&0&0&0&0&0&0&0&0&1&0&0\\ 0&1&0&0&1&0&0&1&1&1&1&1&0&0&0&0&0&0&0&0&0&0&1&0\\ 1&1&0&0&0&1&1&1&0&1&0&1&0&0&0&0&0&0&0&0&0&0&0&1\\ \end{bmatrix} \end{align}

The output of the Golay encoder is shown in the table below.

Field Data Check bits Parity
Position 23..12 11..1 0 (LSB)
Length 12 11 1

Four of these 24-bit blocks are used to reconstruct the LSF.

Sample MATLAB/Octave code snippet for generating G and H matrices is shown below.

Golay(24,12) matrices generator
P = hex2poly('0xC75');
[H,G] = cyclgen(23, P);

G_P = G(1:12, 1:11);
I_K = eye(12);
G = [I_K G_P P.'];
H = [transpose([G_P P.']) I_K];

Convolutional encoder

[ECC]Moreira, Jorge C.; Farrell, Patrick G. “Essentials of Error‐Control Coding” Wiley 2006, ISBN: 9780470029206

The convolutional code shall encode the input bit sequence after appending 4 tail bits at the end of the sequence. Rate of the coder is R=½ with constraint length K=5 [NXDN]. The encoder diagram and generating polynomials are shown below

\begin{align} G_1(D) =& 1 + D^3 + D^4 \\ G_2(D) =& 1+ D + D^2 + D^4 \end{align}

The output from the encoder must be read alternately.

[NXDN]NXDN Technical Specifications, Part 1: Air Interface; Sub-part A: Common Air Interface
_images/convolutional.svg

Convolutional coder diagram

Code puncturing

Removing some of the bits from the convolutional coder’s output is called code puncturing. The nominal coding rate of the encoder used in M17 is ½. This means the encoder outputs two bits for every bit of the input data stream. To get other (higher) coding rates, a puncturing scheme has to be used.

Two different puncturing schemes are used in M17 stream mode:

  1. \(P_1\) leaving 46 from 61 encoded bits
  2. \(P_2\) leaving 11 from 12 encoded bits

Scheme \(P_1\) is used for the link setup frame, taking 488 bits of encoded data and selecting 368 bits. The \(gcd(368, 488)\) is 8 which, when used to divide, leaves 46 and 61 bits. However, a full puncture pattern requires the puncturing matrix entries count to be divisible by the number of encoding polynomials. For this case a partial puncture matrix is used. It has 61 entries with 46 of them being ones and shall be used 8 times, repeatedly. The construction of the partial puncturing pattern \(P_1\) is as follows:

\begin{align} M = & \begin{bmatrix} 1 & 0 & 1 & 1 \end{bmatrix} \\ P_{1} = & \begin{bmatrix} 1 & M_{1} & \cdots & M_{15} \end{bmatrix} \end{align}

In which \(M\) is a standard 2/3 rate puncture matrix and is used 15 times, along with a leading 1 to form \(P_1\), an array of length 61.

The first pass of the partial puncturer discards \(G_1\) bits only, second pass discards \(G_2\), third - \(G_1\) again, and so on. This ensures that both bits are punctured out evenly.

Scheme \(P_2\) is for frames (excluding LICH chunks, which are coded differently). This takes 296 encoded bits and selects 272 of them. Every 12th bit is being punctured out, leaving 272 bits. The full matrix shall have 12 entries with 11 being ones.

The puncturing scheme \(P_2\) is defined by its partial puncturing matrix:

\begin{align} P_2 = & \begin{bmatrix} 1 & 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 & 0 \end{bmatrix} \end{align}

The linearized representations are:

linearized puncture patterns
P1 = [1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1,
1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1]

P2 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]

Interleaving

For interleaving a Quadratic Permutation Polynomial (QPP) is used. The polynomial \(\pi(x)=(45x+92x^2)\mod 368\) is used for a 368 bit interleaving pattern [QPP]. See appendix Table 26 for pattern.

[QPP]Trifina, Lucian, Daniela Tarniceriu, and Valeriu Munteanu. “Improved QPP Interleavers for LTE Standard.” ISSCS 2011 - International Symposium on Signals, Circuits and Systems (2011): n. pag. Crossref. Web. https://arxiv.org/abs/1103.3794

Data decorrelator

To avoid transmitting long sequences of constant symbols (e.g. 010101…), a simple algorithm is used. All 46 bytes of type 4 bits shall be XORed with a pseudorandom, predefined stream. The same algorithm has to be used for incoming bits at the receiver to get the original data stream. See Table 25 for sequence.

Application Layer

Packet Superframes

Packet superframes are composed of a 1..n byte data type specifier, 0..797 bytes of payload data. The data type specifier is encoded in the same way as UTF-8. It provides efficient coding of common data types. And it can be extended to include a very large number of distinct packet data type codes.

The data type specifier can also be used as a protocol specifier. For example, the following protocol identifers are reserved in the M17 packet spec:

Reserved Protocols
Identifer Protocol
0x00 RAW
0x01 AX.25
0x02 APRS
0x03 6LoWPAN
0x04 IPv4
0x05 SMS
0x06 WinLink

The data type specifier is used to compute the CRC, along with the payload.

Encryption Types

Encryption is optional. The use of it may be restricted within some radio services and countries, and should only be used if legally permissible.

Null Encryption

Encryption type = \(00_2\)

No encryption is performed, payload is sent in clear text.

The “Encryption SubType” bits in the Stream Type field then indicate what data is stored in the 112 bits of the LSF META field.

Encryption SubType bits LSF META data contents
\(00_2\) UTF-8 Text
\(01_2\) GNSS Position Data
\(10_2\) Reserved
\(11_2\) Reserved

All LSF META data must be stored in big endian byte order, as throughout the rest of this specification.

GNSS Position Data stores the 112 bit META field as follows:

Size, in bits Format Contents
8 8-bit signed integer Latitude - degrees, integer part (-90..+90, positive values for northern hemisphere)
16 16-bit unsigned integer Latitude - degrees, fractional part (eg. 0.5 -> 32,768)
16 16-bit signed integer Longitude - degrees, integer part (-180..+180, positive values for eastern hemisphere)
16 16-bit unsigned integer Longitude - degrees, fractional part (eg. 0.5 -> 32,768)
16 unsigned integer Altitude, in feet MSL. Stored +1500, so a stored value of 0 represents -1500 MSL. Subtract 1500 feet when parsing.
10 unsigned integer Course in degrees true North
10 unsigned integer Speed in knots
20 Reserved values Transmitter/Object description field

Scrambler

Encryption type = \(01_2\)

Scrambling is an encryption by bit inversion using a bitwise exclusive-or (XOR) operation between bit sequence of data and pseudorandom bit sequence.

Encrypting bitstream is generated using a Fibonacci-topology Linear-Feedback Shift Register (LFSR). Three different LFSR sizes are available: 8, 16 and 24-bit. Each shift register has an associated polynomial. The polynomials are listed in Table 7. The LFSR is initialised with a seed value of the same length as the shift register. Seed value acts as an encryption key for the scrambler algorithm. Figures 5 to 8 show block diagrams of the algorithm

LFSR scrambler polynomials
Encryption subtype LFSR polynomial Seed length Sequence period
\(00_2\) \(x^8 + x^6 + x^5 + x^4 + 1\) 8 bits 255
\(01_2\) \(x^{16} + x^{15} + x^{13} + x^4 + 1\) 16 bits 65,535
\(10_2\) \(x^{24} + x^{23} + x^{22} + x^{17} + 1\) 24 bits 16,777,215
_images/LFSR_8.svg

8-bit LFSR taps

_images/LFSR_16.svg

16-bit LFSR taps

_images/LFSR_24.svg

24-bit LFSR taps

Advanced Encryption Standard (AES)

Encryption type = \(10_2\)

This method uses AES block cipher in counter (CTR) mode, with a 96-bit nonce that should never be used for more than one separate stream and a 32 bit CTR.

The 96-bit AES nonce value is extracted from the 96 most significant bits of the META field, and the remaining 16 bits of the META field form the highest 16 bits of the 32 bit counter. The FN (Frame Number) field value is then used to fill out the lower 16 bits of the counter, and always starts from 0 (zero) in a new voice stream.

The 16 bit frame number and 40 ms frames can provide for over 20 minutes of streaming without rolling over the counter [1].

[1]The effective capacity of the counter is 15 bits, as the MSB is used for transmission end signalling. At 40ms per frame, or 25 frames per second, and 2**15 frames, we get 2**15 frames / 25 frames per second = 1310 seconds, or 21 minutes and some change.

The random part of the nonce value should be generated with a hardware random number generator or any other method of generating non-repeating values.

To combat replay attacks, a 32-bit timestamp shall be embedded into the cryptographic nonce field. The field structure of the 96 bit nonce is shown in Table 9. Timestamp is 32 LSB portion of the number of seconds that elapsed since the beginning of 1970-01-01, 00:00:00 UTC, minus leap seconds (a.k.a. “unix time”).

96 bit nonce field structure
TIMESTAMP RANDOM DATA CTR_HIGH
32 64 16

CTR_HIGH field initializes the highest 16 bits of the CTR, with the rest of the counter being equal to the FN counter.

Warning

In CTR mode, AES encryption is malleable [CTR] [CRYPTO]. That is, an attacker can change the contents of the encrypted message without decrypting it. This means that recipients of AES-encrypted data must not trust that the data is authentic. Users who require that received messages are proven to be exactly as-sent by the sender should add application-layer authentication, such as HMAC. In the future, use of a different mode, such as Galois/Counter Mode, could alleviate this issue [CRYPTO].

[CTR]McGrew, David A. “Counter mode security: Analysis and recommendations.” Cisco Systems, November 2, no. 4 (2002).
[CRYPTO](1, 2) Rogaway, Phillip. “Evaluation of some blockcipher modes of operation.” Cryptography Research and Evaluation Committees (CRYPTREC) for the Government of Japan (2011).

Recommendation for the codeplug structure

Introduction

Codeplugs are ordinary text files with .m17 extension. They provide an information on:

  • channel banks
  • channel frequencies
  • destination IDs
  • transmission mode
  • payload type
  • encryption mode

Codeplugs should be human-readable and easily editable with common text editors.

Codeplug file structure

We recommend using YAML for the codeplug files.

Keywords

codeplug:
author:
String - Codeplug author, max 16 characters
version:
Date and time in YYYY-MM-DDTHH:MM:SS format
bank:
name:
String - Channel bank name, 16 characters maximum
channel:
name:
String - Channel name, 16 characters maximum
descr:
String - Channel Description, 16 characters maximum
freq_rx:
Integer - Channel RX Frequency in Hz
freq_tx:
Integer - Channel TX Frequency in Hz
mode:
Integer - Channel mode. Valid modes are: 0 - Analog, 1 - Digital Voice, 2 - Digital Data, 3 - Digital Voice and Data
encr:
Integer - Is encryption enabled? 0 for no encryption, 1 - AES256, 2 - scrambler etc. (refer to M17_spec for details)
nonce:
String - 14-byte hex value without leading 0x. nonce for ciphers or initial LFSR value for scrambler
gps:
Boolean - If true, and mode value enables digital data, gps data will be transferred along with payload

Example Codeplug

codeplug:
  author: SP5WWP
  version: 2020-28-09T13:20:49
  - bank:
    name: M17
    - channel:
      name: M17_DMO
      descr:
      freq_rx: 439575000
      freq_tx: 439575000
      mode: 2
      encr: 0
      nonce: 0
      gps: false
    - channel:
      name: M17_DMO_2
      descr:
      freq_rx: 439975000
      freq_tx: 439975000
      mode: 2
      encr: 0
      nonce: 0
      gps: false
  - bank:
    name: Repeaters
    - channel:
      name: SR5MS
      descr:
      freq_rx: 439425000
      freq_tx: 431825000
      mode: 2
      encr: 0
      nonce: 0
      gps: false
#codeplug end

Address Encoding

M17 uses 48 bits (6 bytes) long addresses. Callsigns (and other addresses) are encoded into these 6 bytes in the following ways:

  • An address of 0 is invalid.
  • Address values between 1 and 262143999999999 (which is \(40^9-1\)), up to 9 characters of text are encoded using base40, described below.
  • Address values between 262144000000000 (\(40^9\)) and 281474976710654 (\(2^{48}-2\)) are invalid
  • An address of 0xFFFFFFFFFFFF is a broadcast. All stations should receive and listen to this message.
Address scheme
Address Range Category Number of addresses Remarks
0x000000000000 RESERVED 1 For future use
0x000000000001-0xee6b27ffffff Unit ID 262143999999999  
0xee6b28000000-0xfffffffffffe RESERVED 19330976710655 For future use
0xffffffffffff Broadcast 1 Valid only for destination field

Callsign Encoding: base40

9 characters from an alphabet of 40 possible characters can be encoded into 48 bits, 6 bytes. The base40 alphabet is:

  • 0: A space. Invalid characters will be replaced with this.
  • 1-26: “A” through “Z”
  • 27-36: “0” through “9”
  • 37: “-” (hyphen)
  • 38: “/” (slash)
  • 39: “.” (dot)

Encoding is little endian. That is, the right most characters in the encoded string are the most significant bits in the resulting encoding.

Example code: encode_base40()

uint64_t encode_callsign_base40(const char *callsign) {
  uint64_t encoded = 0;
  for (const char *p = (callsign + strlen(callsign) - 1); p >= callsign; p-- ) {
    encoded *= 40;
    // If speed is more important than code space,
    // you can replace this with a lookup into a 256 byte array.
    if (*p >= 'A' && *p <= 'Z') // 1-26
      encoded += *p - 'A' + 1;
    else if (*p >= '0' && *p <= '9') // 27-36
      encoded += *p - '0' + 27;
    else if (*p == '-') // 37
      encoded += 37;
    // These are just place holders. If other characters make more sense,
    // change these. Be sure to change them in the decode array below too.
    else if (*p == '/') // 38
      encoded += 38;
    else if (*p == '.') // 39
      encoded += 39;
    else
      // Invalid character or space, represented by 0, decoded as a space.
      //encoded += 0;
  }
  return encoded;
}

Example code: decode_base40()

char *decode_callsign_base40(uint64_t encoded, char *callsign) {
  if (encoded >= 262144000000000) { // 40^9
    *callsign = 0;
    return callsign;
  }
  char *p = callsign;
  for (; encoded > 0; p++) {
    *p = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."[encoded % 40];
    encoded /= 40;
  }
  *p = 0;

  return callsign;
}

Why base40?

The longest commonly assigned callsign from the FCC is 6 characters. The minimum alphabet of A-Z, 0-9, and a “done” character mean the most compact encoding of an American callsign could be: \(log2(37^6)=31.26\) bits, or 4 bytes.

Some countries use longer callsigns, and the US sometimes issues longer special event callsigns. Also, we want to extend our callsigns (see below). So we want more than 6 characters. How many bits do we need to represent more characters:

bits per characters
characters bits bytes
7 \(log2(37^7)=36.47\) 5
8 \(log2(37^8)=41.67\) 6
9 \(log2(37^9)=46.89\) 6
10 \(log2(37^{10})=52.09\) 7

Of these, 9 characters into 6 bytes seems the sweet spot. Given 9 characters, how large can we make the alphabet without using more than 6 bytes?

alphabet size vs bytes
alphabet size bits bytes
37 \(log2(37^9)=46.89\) 6
38 \(log2(38^9)=47.23\) 6
39 \(log2(39^9)=47.57\) 6
40 \(log2(40^9)=47.90\) 6
41 \(log2(41^9)=48.22\) 7

Given this, 9 characters from an alphabet of 40 possible characters, makes maximal use of 6 bytes.

Callsign Formats

Government issued callsigns should be able to encode directly with no changes.

Multiple Stations

To allow for multiple stations by the same operator, we borrow the use of the ‘-’ character from AX.25 and the SSID field. A callsign such as “AB1CD-1” is considered a different station than “AB1CD-2” or even “AB1CD”, but it is understood that these all belong to the same operator, “AB1CD”

Temporary Modifiers

Similarly, suffixes are often added to callsign to indicate temporary changes of status, such as “AB1CD/M” for a mobile station, or “AB1CD/AE” to signify that I have Amateur Extra operating privileges even though the FCC database may not yet be updated. So the ‘/’ is included in the base40 alphabet. The difference between ‘-’ and ‘/’ is that ‘-’ are considered different stations, but ‘/’ are NOT. They are considered to be a temporary modification to the same station.

Interoperability

It may be desirable to bridge information between M17 and other networks. The 9 character base40 encoding allows for this:

DMR

DMR unfortunately doesn’t have a guaranteed single name space. Individual IDs are reasonably well recognized to be managed by https://www.radioid.net/database/search#! but Talk Groups are much less well managed. Talk Group XYZ on Brandmeister may be (and often is) different than Talk Group XYZ on a private cBridge system.

  • DMR IDs are encoded as: D<number> eg: D3106728 for KR6ZY
  • DMR Talk Groups are encoded by their network. Currently, the following networks are defined:
  • Brandmeister: BM<number> eg: BM31075
  • DMRPlus: DP<number> eg: DP262
  • More networks to be defined here.
D-Star

D-Star reflectors have well defined names: REFxxxY which are encoded directly into base40.

Decorrelator sequence

Decorrelator scrambling sequence
Seq. number Value Seq. number Value
00 0xD6 23 0x6E
01 0xB5 24 0x68
02 0xE2 25 0x2F
03 0x30 26 0x35
04 0x82 27 0xDA
05 0xFF 28 0x14
06 0x84 29 0xEA
07 0x62 30 0xCD
08 0xBA 31 0x76
09 0x4E 32 0x19
10 0x96 33 0x8D
11 0x90 34 0xD5
12 0xD8 35 0x80
13 0x98 36 0xD1
14 0xDD 37 0x33
15 0x5D 38 0x87
16 0x0C 39 0x13
17 0xC8 40 0x57
18 0x52 41 0x18
19 0x43 42 0x2D
20 0x91 43 0x29
21 0x1D 44 0x78
22 0xF8 45 0xC3

Interleaving

Interleaving table
input index output ind input index output ind input index output ind input index output ind
0 0 92 92 184 184 276 276
1 137 93 229 185 321 277 45
2 90 94 182 186 274 278 366
3 227 95 319 187 43 279 135
4 180 96 272 188 364 280 88
5 317 97 41 189 133 281 225
6 270 98 362 190 86 282 178
7 39 99 131 191 223 283 315
8 360 100 84 192 176 284 268
9 129 101 221 193 313 285 37
10 82 102 174 194 266 286 358
11 219 103 311 195 35 287 127
12 172 104 264 196 356 288 80
13 309 105 33 197 125 289 217
14 262 106 354 198 78 290 170
15 31 107 123 199 215 291 307
16 352 108 76 200 168 292 260
17 121 109 213 201 305 293 29
18 74 110 166 202 258 294 350
19 211 111 303 203 27 295 119
20 164 112 256 204 348 296 72
21 301 113 25 205 117 297 209
22 254 114 346 206 70 298 162
23 23 115 115 207 207 299 299
24 344 116 68 208 160 300 252
25 113 117 205 209 297 301 21
26 66 118 158 210 250 302 342
27 203 119 295 211 19 303 111
28 156 120 248 212 340 304 64
29 293 121 17 213 109 305 201
30 246 122 338 214 62 306 154
31 15 123 107 215 199 307 291
32 336 124 60 216 152 308 244
33 105 125 197 217 289 309 13
34 58 126 150 218 242 310 334
35 195 127 287 219 11 311 103
36 148 128 240 220 332 312 56
37 285 129 9 221 101 313 193
38 238 130 330 222 54 314 146
39 7 131 99 223 191 315 283
40 328 132 52 224 144 316 236
41 97 133 189 225 281 317 5
42 50 134 142 226 234 318 326
43 187 135 279 227 3 319 95
44 140 136 232 228 324 320 48
45 277 137 1 229 93 321 185
46 230 138 322 230 46 322 138
47 367 139 91 231 183 323 275
48 320 140 44 232 136 324 228
49 89 141 181 233 273 325 365
50 42 142 134 234 226 326 318
51 179 143 271 235 363 327 87
52 132 144 224 236 316 328 40
53 269 145 361 237 85 329 177
54 222 146 314 238 38 330 130
55 359 147 83 239 175 331 267
56 312 148 36 240 128 332 220
57 81 149 173 241 265 333 357
58 34 150 126 242 218 334 310
59 171 151 263 243 355 335 79
60 124 152 216 244 308 336 32
61 261 153 353 245 77 337 169
62 214 154 306 246 30 338 122
63 351 155 75 247 167 339 259
64 304 156 28 248 120 340 212
65 73 157 165 249 257 341 349
66 26 158 118 250 210 342 302
67 163 159 255 251 347 343 71
68 116 160 208 252 300 344 24
69 253 161 345 253 69 345 161
70 206 162 298 254 22 346 114
71 343 163 67 255 159 347 251
72 296 164 20 256 112 348 204
73 65 165 157 257 249 349 341
74 18 166 110 258 202 350 294
75 155 167 247 259 339 351 63
76 108 168 200 260 292 352 16
77 245 169 337 261 61 353 153
78 198 170 290 262 14 354 106
79 335 171 59 263 151 355 243
80 288 172 12 264 104 356 196
81 57 173 149 265 241 357 333
82 10 174 102 266 194 358 286
83 147 175 239 267 331 359 55
84 100 176 192 268 284 360 8
85 237 177 329 269 53 361 145
86 190 178 282 270 6 362 98
87 327 179 51 271 143 363 235
88 280 180 4 272 96 364 188
89 49 181 141 273 233 365 325
90 2 182 94 274 186 366 278
91 139 183 231 275 323 367 47

M17 Internet Protocol (IP) Networking

Digital modes are commonly networked together through linked repeaters using IP networking.

For commercial protocols like DMR, this is meant for linking metropolitan and state networks together and allows for easy interoperability between radio users. Amateur Radio uses this capability for creating global communications networks for all imaginable purposes, and makes ‘working the world’ with an HT possible.

M17 is designed with this use in mind, and has native IP framing to support it.

In competing radio protocols, a repeater or some other RF to IP bridge is required for linking, leading to the use of hotspots (tiny simplex RF bridges).

The TR-9 and other M17 radios may support IP networking directly, such as through the ubiquitous ESP8266 chip or similar. This allows them to skip the RF link that current hotspot systems require, finally bringing to fruition the “Amateur digital radio is just VoIP” dystopian future we were all warned about.

Standard IP Framing

M17 over IP is big endian, consistent with other IP protocols. We have standardized on UDP port 17000, this port is recommended but not required. Later specifications may require this port.

Internet frame fields
MAGIC 32 bits Magic bytes 0x4d313720 (“M17 “)
StreamID (SID) 16 bits Random bits, changed for each PTT or stream, but consistent from frame to frame within a stream
LICH 240 bits The meaningful contents of a LICH frame (dst, src, streamtype, META field, CRC16) as defined earlier.
FN 16 bits Frame number (exactly as would be transmitted as an RF stream frame, including the last frame indicator at (FN & 0x8000)
Payload 128 bits Payload (exactly as would be transmitted in an RF stream frame)
CRC16 16 bits CRC for the entire packet, as defined earlier (TODO: specific link)

The CRC checksum must be recomputed after modification or re-assembly of the packet, such as when translating from RF to IP framing.

Control Packets

Reflectors use a few different types of control frames, identified by their magic:

  • CONN - Connect to a reflector
  • ACKN - acknowledge connection
  • NACK - deny connection
  • PING - keepalive for the connection from the reflector to the client
  • PONG - keepalive response from the client to the reflector
  • DISC - Disconnect (client->reflector or reflector->client)

CONN

Bytes of a CONN packet
Bytes Purpose
0-3 Magic - ASCII “CONN”
4-9 6-byte ‘From’ callsign including module in last character (e.g. “A1BCD D”) encoded as per Address Encoding
10 Module to connect to - single ASCII byte A-Z

A client sends this to a reflector to initiate a connection. The reflector replies with ACKN on successful linking, or NACK on failure.

ACKN

Bytes of ACKN packet
Bytes Purpose
0-3 Magic - ASCII “ACKN”

NACK

Bytes of NACK packet
Bytes Purpose
0-3 Magic - ASCII “NACK”

PING

Bytes of PING packet
Bytes Purpose
0-3 Magic - ASCII “PING”
4-9 6-byte ‘From’ callsign including module in last character (e.g. “A1BCD D”) encoded as per Address Encoding

Upon receivng a PING from a reflector, the client replies with a PONG

PONG

Bytes of PONG packet
Bytes Purpose
0-3 Magic - ASCII “PONG”
4-9 6-byte ‘From’ callsign including module in last character (e.g. “A1BCD D”) encoded as per Address Encoding

DISC

Bytes of DISC packet
Bytes Purpose
0-3 Magic - ASCII “DISC”
4-9 6-byte ‘From’ callsign including module in last character (e.g. “A1BCD D”) encoded as per Address Encoding

Sent by either end to force a disconnection. Acknowledged with 4-byte packet “DISC” (without the callsign field)

KISS Protocol

The purpose of this appendix is to document conventions for adapting KISS TNCs to M17 packet and streaming modes. M17 is a more complex protocol, both at the baseband level and at the data link layer than is typical for HDLC-based protocols commonly used on KISS TNCs. However, it is well suited for modern packet data links, and can even be used to stream digital audio between a host and a radio.

This appendix assumes the reader is familiar with the streaming and packet modes defined in the M17 spec, and with KISS TNCs and the KISS protocol.

In all cases, the TNC expects to get the data payload to be sent and is responsible for frame construction, FEC encoding, puncturing, interleaving and decorrelation. It is also responsible for baseband modulation.

For streaming modes, all voice encoding (Codec2) is done on the host and not on the TNC. The host is also responsible for constructing the LICH.

Glossary

TNC
Terminal node controller – a baseband network interface device to allow host computers to send data over a radio network, similar to a modem. It connects a computer to a radio and handles the baseband portion of the physical layer and the data link layer of network protocol stack.
KISS
Short for “Keep it simple, stupid”. A simplified TNC protocol designed to move everything except for the physical layer and the data link layer out of the TNC. Early TNCs could include everything up through the application layer of the OSI network model.
SLIP
Serial Line Internet Protocol – the base protocol used by the KISS protocol, extended by adding a single type indicator byte at the start of a frame.
type indicator
A one byte code at the beginning of a KISS frame which indicates the TNC port and KISS command.
port
A logical port on a TNC. This allowed a single TNC to connect to multiple radios. Its specific use is loosely defined in the KISS spec. The high nibble of the KISS type indicator. Port 0xF is reserved.
command
A KISS command. This tells the TNC or host how to interpret the KISS frame contents. The low nibble of the KISS type indicator. Command 0xF is reserved.
CSMA
Carrier-sense multiple access – a protocol used by network devices to minimize collisions on a shared communications channel.
HDLC
High-Level Data Link Control – a data link layer framing protocol used in many AX.25 packet radio networks. Many existing protocol documents, including KISS, reference HDLC because of its ubiquity when the protocols were invented. However, HDLC is not a requirement for higher level protocols like KISS which are agnostic to the framing used at the data link layer.
EOS
End of stream – an indicator bit in the frame number field of a stream data frame.
LICH
Link information channel – a secondary data channel in the stream data frame containing supplemental information, including a copy of the link setup frame.

M17 Protocols

This specification defines KISS TNC modes for M17 packet and streaming modes, allowing the KISS protocol to be used to send and receive M17 packet and voice data. Both are bidirectional. There are two packet modes defined. This is done to provide complete access to the M17 protocol while maintaining the greatest degree of backwards compatibility with existing packet applications.

These protocols map to specific KISS port. The host tells the TNC what type of data to transmit based on the port used in host to TNC transfers. And the TNC tells the host what data it has received by the port set on TNC to host transfers.

This document outlines first the two packet protocols, followed by the streaming protocol.

KISS Basics

TX Delay

If a KISS TX delay \(T_d\) greater than 0 is specified, the transmitter is keyed for \(T_d * 10 ms\) with only a DC signal present.

The \(T_d\) value should be adjusted to the minimum required by the transmitter in order to transmit the full preamble reliably.

Only a single 40ms preamble frame is ever sent.

Note

A TX delay may be necessary because many radios require some time between when PTT is engaged and the transmitter can begin transmitting a modulated signal.

Packet Protocols

In order to provide backward compatibility with the widest range of existing ham radio software, and to make use of features in the the M17 protocol itself, we will define two distint packet interfaces BASIC and FULL.

The KISS protocol allows us to target specific modems using the port identifier in the control byte.

We first define basic packet mode as this is initially likely to be the most commonly used mode over KISS.

M17 Basic Packet Mode

Basic packet mode uses only the standard KISS protocol on TNC port 0. This is the default port for all TNCs. Packets are sent using command 0. Again, this is normal behavior for KISS client applications.

Sending Data

In basic mode, the TNC only expects to receive packets from the host, as it would for any other mode supported AFSK, G3RUH, etc.

If the TNC is configured for half-duplex, the TNC will do P-persistence CSMA using a 40ms slot time and obey the P value set via the KISS interface. CSMA is disabled in full-duplex mode.

The TX Tail value is deprecated and is ignored.

The TNC sends the preamble burst.

The TNC is responsible for constructing the link setup frame, identifying the content as a raw mode packet. The source field is an encoded TNC identifier, similar to the APRS TOCALL, but it can be an arbitrary text string up to 9 characters in length. The destination is set to the broadcast address.

In basic packet mode, it is expected that the sender callsign is embedded within the packet payload.

The TNC sends the link setup frame.

The TNC then computes the CRC for the full packet, splits the packet into data frames encode and modulate each frame back-to-back until the packet is completely transmitted.

If there is another packet to be sent, the preamble can be skipped and the TNC will construct the next link setup frame (it can re-use the same link setup frame as it does not change) and send the next set of packet frames.

Limitations

The KISS specification defines no limitation to the packet size allowed. Nor does it specify any means of returning error conditions back to the host. M17 packet protocol limits the raw packet payload size to 798 bytes. The TNC must drop any packets larger than this.

Receiving Data

When receiving M17 data, the TNC must receive and parse the link setup frame and verify that the following frames contain raw packet data.

The TNC is responsible for decoding each packet, assembling the packet from the sequence of frames received, and verifying the packet checksum. If the checksum is valid, the TNC transfers the packet, excluding the CRC to the host using KISS port 0.

M17 Full Packet Mode

The purpose of full packet mode is to provide access to the entire M17 packet protocol to the host. This allows the host to set the source and destination fields, filter received packets based on the content these fields, enable encryption, and send and receive type-coded frames.

Use M17 full packet mode by sending to KISS port 1. In this mode the host is responsible for sending both the link setup frame and the packet data. It does this by prepending the 30-byte link setup frame to the packet data, sending this to the TNC in a single KISS frame. The TNC uses the first 30 bytes as the link setup frame verbatim, then splits the remaining data into M17 packet frames.

As with basic mode, the TNC uses the Duplex setting to enable/disable CSMA, and uses the P value for CSMA, with a fixes slot time of “4” (40 ms).

Receiving Data

For TNC to host transfers, the same occurs. The TNC combines the link setup frame with the packet frame and sends both in one KISS frame to the host using KISS port 1.

Stream Protocol

The streaming protocol is fairly trivial to describe. It is used by sending first a link setup frame followed by a stream of 26-byte data frames to KISS port 2.

Stream Format

M17 KISS Stream Protocol
Frame Size Contents
30 Link Setup Frame
26 LICH + Payload
26 LICH + Payload
26 LICH + Payload with EOS bit set.

The host must not send any frame to any other KISS port while a stream is active (a frame with the EOS bit has not been sent).

It is a protocol violation to send anything other than a link setup frame with the stream mode bit set in the first field as the first frame in a stream transfer to KISS port 2. Any such frame is ignored.

It is a protocol violation to send anything to any other KISS port while a stream is active. If that happens the stream is terminated and the packet that caused the protocol violation is dropped.

Data Frames

The data frames contain a 6-byte (48-bit) LICH segment followed by a 20 byte payload segment consisting of frame number, 16-byte data payload and CRC. The TNC is responsible for parsing the frame number and detecting the end-of-stream bit to stop transmitting.

KISS Stream Data Frame
Frame Size Contents
6 LICH (48 bits)
2 Frame number and EOS flag
16 Payload
2 M17 CRC of frame number and payload

The TNC is responsible for FEC-encoding both the LICH the payload, as well as interleaving, decorrelation, and baseband modulation.

Timing Constraints

Streaming mode provides additional timing constraints on both host to TNC transfers and on TNC to host transfers. Payload frames must arrive every 40ms and must have a jitter below 40ms. In general, it is expected that the TNC has up to 2 frames buffered (buffering occurs while sending the preamble and link setup frames), it should be able to keep the transmit buffers filled with packet jitter of 40ms.

The TNC must stop transmitting if the transmit buffers are empty. The TNC communicates that it has stopped transmitting early (before seeing a frame with the end of stream indicator set) by sending an empty data frame to the host.

TNC to Host Transfers

TNC to host transfers are similar in that the TNC first sends the 30-byte link setup frame received to the host, followed by a stream of 26-byte data frames as described above. These are sent using KISS port 2.

The TNC must send the link setup frame first. This means that tne TNC must be able to decode LICH segments and assemble a valid link setup frame before it sends the first data frame. The TNC will only send a link setup frame with a valid CRC to the host. After the link setup frame is sent, the TNC ignores the CRC and sends all valid frames (those received after a valid sync word) to the host. If the stream is lost before seeing an end-of-stream flag, the TNC sends a 0-byte data frame to indicate loss of signal.

The TNC must then re-acquire the signal by decoding a valid link setup frame from the LICH in order to resume sending to the host.

Busy Channel Lockout

The TNC implements busy channel lockout by enabling half-duplex mode on the TNC, and disables busy channel lockout by enabling full-duplex mode. When busy channel lockout occurs, the TNC keeps the link setup frame and discards all data frames until the channel is available. It then sends the preamble, link setup frame, and starts sending the data frames as they are received.

Note: BCL will be apparent to a receiver as the first frame received after the link setup frame will not start with frame number 0.

Limitations

Information is lost by having the TNC decode the LICH. It is not possible to communicate to the host that the LICH bytes are known to be invalid.

Should we have the TNC signal the host by dropping known invalid LICH segments? The host can tell that the LICH is missing by looking at the frame size.

Mixing Modes

An M17 KISS TNC need not keep track of state across distinct TNC ports. Packet transfers are sent one packet at a time. It is OK to send to port 0 and port 1 in subsequent transfers. It is also OK to send a packet followed immediately by a voice streams. As mentioned earlier, it is a protocol violation to sent a KISS frame to any other port while a stream is active. However, a packet can be sent immediately following a voice stream (after EOS is sent).

Back-to-back Transfers

The TNC is expected to detect back-to-back transfers from the host, even across different KISS ports, and suppress the generation of the preamble.

For example, a packet containing APRS data sent immediately on PTT key-up should be sent immediately after the EOS frame.

Back-to-back transfers are common for packet communication where the window size determines the number of unacknowledged frames which may be outstanding (unacknowledged). Packet applications will frequently send back-to-back packets (up to window size packets) before waiting for the remote end to send ACKs for each of the packets.

Implementation Details

Polarity

One of the issues that must be addressed by the TNC designer, and one which the KISS protocol offers no ready solution for, is the issue of polarity.

A TNC must interface with a RF transceiver for a complete M17 physical layer implementation. RF transceivers may have different polarity for their TX and RX paths.

M17 defines that the +3 symbol is transmitted with a +2.4 kHz deviation (2.4 kHz above the carrier). Normal polarity in a transceiver results in a positive voltage driving the frequency higher and a lower voltage driving the frequency lower. Reverse polarity is the opposite. A higher voltage drives the frequency lower.

On the receive side the same issue exists. Normal polarity results in a positive voltage output when the received signal is above the carrier frequency. Reverse polarity results in a positive voltage when the frequency is below the carrier.

Just as with transmitter deviation levels and received signal levels, the polarity of the transmit and receive path must be adjustable on a 4-FSK modem. The way these adjustments are made to the TNC are not addressed by the KISS specification.