Skip to content
Snippets Groups Projects
standard.tex 37.4 KiB
Newer Older
Stephen D's avatar
Stephen D committed
\documentclass{article}

Stephen D's avatar
Stephen D committed
\usepackage{tabularx, tikz, amsmath, gensymb, titlepic, graphicx, listings, makecell}
Stephen D's avatar
Stephen D committed
\usepackage[margin=1in]{geometry}

\usetikzlibrary{shapes,arrows,fit}
\tikzstyle{block} = [draw, rectangle, text width=2cm, text centered, minimum height=1.2cm, node distance=3cm]

Stephen D's avatar
Stephen D committed
\definecolor{codegreen}{rgb}{0,0.6,0}
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
\definecolor{codepurple}{rgb}{0.58,0,0.82}
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}

\lstdefinestyle{mystyle}{
    backgroundcolor=\color{backcolour},
    commentstyle=\color{codegreen},
    keywordstyle=\color{magenta},
    numberstyle=\tiny\color{codegray},
    stringstyle=\color{codepurple},
    basicstyle=\ttfamily\footnotesize,
    breakatwhitespace=false,
    breaklines=true,
    captionpos=b,
    keepspaces=true,
    numbers=left,
    numbersep=5pt,
    showspaces=false,
    showstringspaces=false,
    showtabs=false,
    tabsize=2
}

\lstset{style=mystyle}

Stephen D's avatar
Stephen D committed
\begin{document}

Stephen D's avatar
Stephen D committed
\title{CATS --- Communication And Telemetry System \\ \large Protocol Standard}
Stephen D's avatar
Stephen D committed
\author{scd31.com}
\titlepic{\includegraphics{logo/logo.png}}
\maketitle

\newpage

\begin{abstract}
Stephen D's avatar
Stephen D committed
  APRS, while an excellent tool, is over 20 years old, and is beginning to show its age. The protocol itself is overly complex, and not particularly efficient. The modulation on which it rests --- AFSK over FM --- is also sub-optimal. The purpose of CATS is to design a modernized solution that overcomes these challenges by utilizing the latest technologies. CATS aims to deliver enhanced efficiency, simplicity in implementation, and improved performance compared to APRS.
Stephen D's avatar
Stephen D committed
\end{abstract}

\newpage

\tableofcontents

\newpage

\section{Introduction}

\subsection{Features of CATS}

Stephen D's avatar
Stephen D committed
CATS has many exciting features over APRS:
Stephen D's avatar
Stephen D committed

\begin{itemize}
Stephen D's avatar
Stephen D committed
\item 2-FSK is used instead of FM-AFSK for a 12 dB coding gain
Stephen D's avatar
Stephen D committed
\item Forward Error Correction (LDPC), further improving the coding gain
\item Bit-rate increased from 1200 bits/s to 9600 bits/s
\item Maximum packet size 8191 bytes
\item Data whitening used to prevent receiver desynchronization
Stephen D's avatar
Stephen D committed
\item The 70cm band is used instead of the 2m band by default
Stephen D's avatar
Stephen D committed
  \begin{itemize}
Stephen D's avatar
Stephen D committed
  \item Since 2m is more common for voice, it makes it easy to add CATS to an existing setup while still being able to use 2m repeaters --- with full duplexing, so that CATS transmissions do not cause loss of reception on 2m
Stephen D's avatar
Stephen D committed
  \end{itemize}
\item FELINET, which is the CATS equivalent of APRS-IS, will push and pull messages from APRS-IS to maintain some compatibility, at least initially. The eventual goal is to drop this link.
\end{itemize}

\subsection{The Pipeline}

CATS packets are created from raw information using the following flow. For reception, the pipeline is reversed. Note that all multi-byte fields are encoded little-endian unless otherwise indicated. \\

\begin{tikzpicture}

    \node [block, name=text1] {Raw data};
    \node [block, right of=text1] (text2) {Whiskers};
    \node [block, right of=text2] (text3) {CRC};
    \node [block, right of=text3] (text4) {Whitener};
    \node [block, below of=text4] (text5) {LDPC};
Stephen D's avatar
Stephen D committed
    \node [block, below of=text3] (text6) {Interleaver};
    \node [block, below of=text2] (text7) {Header};
    \node [block, below of=text1] (text8) {RF};

    \draw [->] (text1) -- (text2);
    \draw [->] (text2) -- (text3);
    \draw [->] (text3) -- (text4);
    \draw [->] (text4) -- (text5);
    \draw [->] (text5) -- (text6);
    \draw [->] (text6) -- (text7);
    \draw [->] (text7) -- (text8);

\end{tikzpicture}

\subsection{Invalid CATS Packets}

Stephen D's avatar
Stephen D committed
The APRS standard is plagued by the existence of invalid packets. A good APRS parser not only handles valid packets --- it also handles slightly malformed ones. Different parsers may handle malformed packets differently, since by definition, they are not in a unified standard. This complicates new implementations and leads to fragmentation of the ecosystem.
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
CATS aims to avoid this problem. A packet that does not conform rigidly to the standard must have its contents discarded. Even if only one whisker is malformed, all whiskers must be ignored. It is considered an implementation bug if this does not occur. Note that unknown whisker types are not invalid. This allows for future whisker types to be added without breaking compatibility with existing implementations.
Stephen D's avatar
Stephen D committed

\section{Whiskers}

\subsection{Overview}

One main feature of CATS is that packets are constructed from Whiskers. Each Whisker represents one possible attribute of data. One CATS packet can have up to 255 Whiskers, so long as the 8191-byte limit is respected. There are many types of Whiskers:

\begin{table}[!ht]
\setlength\extrarowheight{2pt}
\begin{tabularx}{\textwidth}{|X|X|}
  \hline
  \textbf{Whisker Type} & \textbf{Notes} \\
  \hline
  Identification & Contains the source callsign \\
  \hline
  Timestamp & \\
  \hline
  GPS & \\
  \hline
  Comment & \\
  \hline
  Route & The path that the packet took because the source station and the current station \\
  \hline
  Destination & Who the CATS packet is destined for \\
  \hline
  Arbitrary & Arbitrary array of bytes, intentionally not understood by CATS \\
  \hline
  Simplex & A frequency for voice communications \\
  \hline
  Repeater & Information for communicating with a repeater \\
  \hline
Stephen D's avatar
Stephen D committed
\end{tabularx}
\end{table}

\subsection {Structure}

Each Whisker has the same general structure.

\begin{tabular}{|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Data} \\
  \hline
  0 & 1 & Whisker type \\
  \hline
  1 & 1 & Whisker length in bytes $N$ \\
  \hline
  2 & $N$ & Whisker data \\
  \hline
\end{tabular} \\

If there are multiple Whiskers in a CATS packet, their bytes are concatenated together. Since the Whisker length is encoded as a single byte, it means the actual data (not including the type or length bytes) is a maximum of 255 bytes per Whisker. Also, because the length is encoded in the same place in each Whisker, a decoder does not need to support every type. If it sees a type it does not recognize, it can skip the next $N$ bytes and continue onto the next Whisker.
Stephen D's avatar
Stephen D committed

\section{CRC}

\subsection{Overview}

A CRC checksum is used to distinguish when a CATS packet is corrupt. In this case, the packet should be discarded.

\subsection{Structure}

Stephen D's avatar
Stephen D committed
The CRC algorithm used is the 16-bit IBM SDLC CRC algorithm. \\
Stephen D's avatar
Stephen D committed

\begin{tabular}{|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Data} \\
  \hline
  0 & $N$ & Compressed Data \\
  \hline
  $N$ & 2 & CRC checksum \\
  \hline
\end{tabular}

\section{Whitener}

\subsection{Overview}

Data whitening is a technique employed to enhance the randomness of data, making it resemble white noise to a greater extent. This process offers several advantages, with the elimination of prolonged sequences of repetitive bits being the most significant one. Ensuring such elimination is crucial to prevent synchronization issues between the transmitter and receiver.

Stephen D's avatar
Stephen D committed
In CATS, the data is XORed with the output of a 16-bit Galois linear-feedback shift register (LFSR) with a start state of 0xE9CF and taps at 16, 14, 13, and 11. The output stream is used to construct the whitening sequence, one byte at a time, starting from the MSB and moving to the LSB. For example, the first 16 bytes of data should be XORed with ``F38D D06E 1F65 7575 A5BA A9D0 7A1D 0121''.
Stephen D's avatar
Stephen D committed
\section{LDPC}

\subsection{Overview}

Stephen D's avatar
Stephen D committed
In APRS, a single flipped bit results in a ruined packet. In CATS, Forward Error Correction (FEC) is used to make the protocol tolerant of bit flips. LDPC has been chosen, as it is a mature algorithm which operates close to the Shannon Limit.
Stephen D's avatar
Stephen D committed

\subsection{Algorithm}

Stephen D's avatar
Stephen D committed
Like APRS, CATS packets are variable-length. This is advantageous as packets that contain small amounts of data don't need to be padded; this increases efficiency. However, LDPC encoding requires data to be of a constant width. The solution is to break our data into chunks, so that we can LDPC-encode each chunk individually.
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
The structure of the data chunks is not encoded in the packet. Instead, the data is broken into chunks deterministically. The same algorithm can be used by the receiver to break the chunks apart, decode them, and combine the resulting data together. The valid LDPC codes are TC128, TC256, TC512, TM2048, and TM8192, all with $r=1/2$. These codes are specified in detail in CCSDS document 231.1-0-1. The algorithm works as follows:
Stephen D's avatar
Stephen D committed

\begin{enumerate}
\item Pick the largest code with an input size $M \le N$
\item Take the first M bytes of data and pass them through the LDPC encoder
\item Set $N \leftarrow M - N$
Stephen D's avatar
Stephen D committed
\item Go to step 1, unless $N \le 32$ bits
Stephen D's avatar
Stephen D committed
\item Pad the remaining data with 0xAA to make it 8 bytes long
\item Run the padded data through TC128 encoder
\end{enumerate}

Note that on the final step, the 0xAA padding doesn't end up in the final packet. Only the original data and the parity data is included. \\

For example, imagine our data after adding the parity CRC is 2349 bytes long. The algorithm would work as follows:
\begin{enumerate}
\item Encode the first 512 bytes with TM8192 (1837 bytes remaining)
\item Encode the next 512 bytes with TM8192 (1325 bytes remaining)
\item Encode the next 512 bytes with TM8192 (813 bytes remaining)
\item Encode the next 512 bytes with TM8192 (301 bytes remaining)
\item Encode the next 128 bytes with TM2048 (173 bytes remaining)
\item Encode the next 128 bytes with TM2048 (45 bytes remaining)
\item Encode the next 32 bytes with TC512 (13 bytes remaining)
\item Encode the next 8 bytes with TC128 (5 bytes remaining)
\item Pad the remaining 5 bytes out to 8 bytes with 0xAA 0xAA 0xAA, then encode with TC128
\end{enumerate}

Stephen D's avatar
Stephen D committed
Note that the final packet length will be:
Stephen D's avatar
Stephen D committed
\begin{align*}
  L &= 2 + N + (512 * 4) + (128 * 2) + 32 + (8 * 2)\\
  &= 4703
\end{align*}

\subsection{Structure}

\begin{tabularx}{\textwidth}{|l|l|X|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Data} \\
  \hline
Stephen D's avatar
Stephen D committed
  0 & $D_1$ & First data chunk \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  $D_1$ & $D_2$ & Second data chunk \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  $D_1 + D_2$ & $D_3$ & Third data chunk \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  ... & ... & ... \\
  \hline
Stephen D's avatar
Stephen D committed
  $\sum_{i=1}^{n-1} D_i$ & $D_n$ & $n$th data chunk \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  $\sum_{i=1}^{n} D_i$ & $P_1$ & LDPC parity for first chunk \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  $\sum_{i=1}^{n} D_i + P_1$ & $P_2$ & LDPC parity for second chunk \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  $\sum_{i=1}^{n} D_i + P_1 + P_2$ & $P_3$ & LDPC parity for third chunk \\
Stephen D's avatar
Stephen D committed
  \hline
  ... & ... & ... \\
  \hline
Stephen D's avatar
Stephen D committed
  $\sum_{i=1}^{n} D_i + \sum_{i=1}^{n-1} P_i$ & $P_n$ & LDPC parity for $n$th chunk \\
  \hline
  $\sum_{i=1}^{n} D_i + \sum_{i=1}^{n} P_i$ & 2 & Number of bytes after adding CRC parity (pre-LDPC encoding) \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
\end{tabularx}

\section{Interleaver}

\subsection{Overview}

LDPC makes our CATS packet robust against single bit flips. However, it is not particularly robust against burst errors. This is because a burst will flip several bits in only one (or possibly two) of our LDPC chunks, while the rest remain untouched. If too many bits flip in a single chunk, it will not be possible to recover. Instead, it is better to split this burst across as many chunks as possible, to lower the likelihood that a chunk will be unrecoverable. The interleaver is responsible for reordering the CATS bits in such a way to be robust against bit flips.

Stephen D's avatar
Stephen D committed
In CATS, a 32-bit block interleaver is used. For a bit-string input $b_0 b_1 b_2 b_3 ... b_n$, the output from the interleaver is $b_0 b_{32} b_{64} ... b_1 b_{33} b_{65} ... b_3 b_{34} b_{66} ...$ . The receiver is responsible for de-interleaving the bit stream to get the original data.
Stephen D's avatar
Stephen D committed

\section{Header}

\subsection{Overview}

Before transmission, a header must be affixed to the packet. This is used so that the receiver can detect the packet and synchronize with the transmitter's phase. It's also used so that the receiver knows how many bytes to listen for before attempting to decode.

\subsection{Structure}

\begin{tabular}{|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Data} \\
  \hline
  0 & 4 & Preamble (0x55 0x55 0x55 0x55) \\
  \hline
  4 & 4 & Sync word (0xAB 0xCD 0xEF 0x12) \\
  \hline
  8 & 2 & Data length in bytes, $L$ \\
  \hline
  10 & $L$ & LDPC-encoded data \\
  \hline
\end{tabular}

Note that $L \le 8191$.

\section{RF}

\subsection{Overview}

Stephen D's avatar
Stephen D committed
After affixing the header, the packet is ready to be transmitted as RF. The following modulation parameters should be used:
Stephen D's avatar
Stephen D committed

\begin{itemize}
\item Modulation Scheme: 2-FSK
\item Bit rate: 9600 bits/s
\item Deviation: 4.8 KHz
Stephen D's avatar
Stephen D committed
\item Frequency: 430.500 MHz
\item Sum of transmission ramp-up/ramp-down time: $< 1$ ms
Stephen D's avatar
Stephen D committed
\end{itemize}

\section{Whisker Types}

\subsection{Identification}

As an example of CATS' extreme flexibility, even the packet's identification exists in a whisker. When using CATS as intended, this whisker will likely always be included. There are some situations where it may not be, however. For example, to save data it could be omitted in some packets, as long as it is included often enough for legal station identification. It could also be omitted if CATS is being used outside of amateur frequencies. \textbf{A valid CATS packet contains a maximum of one identification whisker.}

Stephen D's avatar
Stephen D committed
The callsign is an arbitrary string of UTF-8 up to 252 bytes long. In most cases, it should be much shorter. One remaining byte at the end is for the SSID. This allows up to 255 different stations to share a single callsign.

The identification whisker also has 2 bytes which specify an icon. CATS icons are loosely equivalent to APRS symbols. Two bytes allows a maximum of 65536 different icons. For now, only a handful are defined, though this list will evolve with the standard. All icon IDs are valid, even those that don't currently correspond with an icon. This property is essential to allow the icon list to grow while ensuring backwards-compatibility with older nodes.
Stephen D's avatar
Stephen D committed

\subsubsection{Structure}

\begin{tabularx}{\textwidth}{|l|l|l|X|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x00 & Whisker type \\
Stephen D's avatar
Stephen D committed
  \hline
  1 & 1 & $N$ & Whisker length in bytes \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  2 & 2 & & Icon ID \\
  \hline
  4 & $N - 3$ & & Callsign data \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  $N + 1$ & 1 & & SSID \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabularx}

Stephen D's avatar
Stephen D committed
\subsubsection{Icon Table}

\begin{tabular}{|l|l|}
  \hline
  \textbf{Icon ID} & \textbf{Icon Name} \\
  \hline
  0 & [No Icon] \\
  \hline
  1 & Cat \\
  \hline
  2 & Car \\
  \hline
  3 & House \\
  \hline
  4 & Office building \\
  \hline
  5 & Truck \\
  \hline
  6 & Van \\
  \hline
  7 & Red Square \\
  \hline
  8 & Orange Square \\
  \hline
  9 & Yellow Square \\
  \hline
  10 & Green Square \\
  \hline
  11 & Blue Square \\
  \hline
  12 & Purple Square \\
  \hline
  13 & Balloon \\
  \hline
Stephen D's avatar
Stephen D committed
  14 & Airplane \\
Stephen D's avatar
Stephen D committed
  \hline
  15 & Helicopter \\
  \hline
  16 & Bus \\
  \hline
  17 & Train \\
  \hline
  18 & Person \\
  \hline
  19 & Warning \\
  \hline
  20 & Error \\
  \hline
  21 & Satellite \\
  \hline
  22 & Computer \\
  \hline
Stephen D's avatar
Stephen D committed
  23 & Bicycle \\
  \hline
Stephen D's avatar
Stephen D committed
  24 & Motorcycle \\
  \hline
Stephen D's avatar
Stephen D committed
\end{tabular}

Stephen D's avatar
Stephen D committed
\subsection{Timestamp}

Stephen D's avatar
Stephen D committed
The timestamp whisker is used to mark the time that a CATS packet occurred at. It is encoded in the Unix timestamp --- that is, seconds since January 1, 1970, in the UTC timezone.
Stephen D's avatar
Stephen D committed

\subsubsection{Structure}

\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x01 & Whisker type \\
Stephen D's avatar
Stephen D committed
  \hline
  1 & 1 & 5 & Whisker length in bytes \\
Stephen D's avatar
Stephen D committed
  \hline
  2 & 5 & & Current time (Unix timestamp) \\
  \hline
\end{tabular}

\subsection{GPS}

The GPS whisker is used to encode latitude, longitude, altitude, precision, heading, and speed. The latitude, longitude, and altitude define a precise point in 3D space. An error is specified in meters. This defines a sphere in space, of which the actual location is somewhere inside. If the latitude, longitude, and altitude are precise, the error should be 0. \textbf{A valid CATS packet contains a maximum of one GPS whisker.}

\subsubsection{Structure}

{\def\arraystretch{1.3}
\begin{tabularx}{\textwidth}{|l|l|l|X|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x02 & Whisker type \\
Stephen D's avatar
Stephen D committed
  \hline
  1 & 1 & 14 & Whisker length in bytes \\
Stephen D's avatar
Stephen D committed
  \hline
  2 & 4 & & Latitude (signed integer, ${2^{31} \over 90 \degree}x$) \\
  \hline
  6 & 4 & & Longitude (signed integer, ${2^{31} \over 180 \degree}x$) \\
  \hline
Stephen D's avatar
Stephen D committed
  10 & 2 & & Altitude (16-bit float, meters) \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  12 & 1 & & Maximum location error (unsigned integer, meters) \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  13 & 1 & & Heading (unsigned integer, radians$* {128\over{\pi}}$). Clockwise relative to north \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  14 & 2 & & Speed (16-bit float, meters per second) \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabularx}
}

\subsection{Comment}

Stephen D's avatar
Stephen D committed
The comment whisker specifies a textual comment on the CATS packet. The content is an arbitrary byte string. \textbf{A valid CATS packet may contain zero or more comment whiskers.} In this case, their content should be concatenated together. This allows for comments longer than 255 bytes. After concatenation, the result must be valid UTF-8. Note that an individual comment whisker may or may not be valid UTF-8.
Stephen D's avatar
Stephen D committed

\subsubsection{Structure}

\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x03 & Whisker type \\
Stephen D's avatar
Stephen D committed
  \hline
  1 & 1 & $N$ & Whisker length in bytes \\
Stephen D's avatar
Stephen D committed
  \hline
  2 & $N$ & & Comment content \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabular}

\subsection{Route}

The route of a CATS packet is an ordered list of stations which have digipeated the packet. Each station consists of a callsign of arbitrary length, as well as a 1-byte SSID. The callsign must be valid UTF-8. This is identical to what is allowed in an identification whisker. \textbf{A valid CATS packet contains a maximum of one route whisker.}

Each callsign is represented as a set of bytes, which are valid UTF-8. After the last byte of the callsign should be a single byte of 0xFF, which acts as a delimiter. The next byte is the SSID for that callsign, proceeded by an RSSI byte. Following that is the beginning of the next callsign. To represent a hop over the Internet, the byte 0xFE is used. This byte must be put where the start of a callsign is detected. The following byte will be used as the start of the callsign for the following hop. Multiple 0xFE bytes may be used in succession to represent multiple hops over the Internet.
Stephen D's avatar
Stephen D committed

Instead of the 0xFF delimiter, 0xFD may be used. This signifies that the previous callsign is not part of the route yet. The first callsign in the route with a 0xFD delimiter must be the next digipeater. No other digipeaters should repeat the packet. A route may consist of a mixture of 0xFF and 0xFD delimiters, as long as there are no 0xFF delimiters after the first 0xFD delimiter.

A callsign with a 0xFF delimiter is known as a ``past'' hop. A callsign with a 0xFD delimiter is known as a ``future'' hop.

Stephen D's avatar
Stephen D committed
The route whisker also contains a maximum amount of hops. This does not include Internet links. The maximum hops is not decremented --- instead, the number of callsigns in the route whisker is compared to the maximum number of hops to determine if a packet should be digipeated.
Stephen D's avatar
Stephen D committed

When digipeating, the callsign of the digipeater should be added to the route. The CATS packet should not be modified beyond this.

\subsubsection{Structure}

\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x04 & Whisker type \\
Stephen D's avatar
Stephen D committed
  \hline
  1 & 1 & $N$ & Whisker length in bytes \\
Stephen D's avatar
Stephen D committed
  \hline
  2 & 1 & & Maximum allowable digipeats \\
  \hline
  3 & $N - 1$ & & Callsigns, SSIDs, and RSSI values \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabular}

Stephen D's avatar
Stephen D committed
\subsubsection{RSSI}

Stephen D's avatar
Stephen D committed
Each node in the route has a byte that indicates the RSSI. This is the RSSI that the node received the packet at. For a given value $x$, representing the RSSI in dBm, the value encoded in the RSSI byte is $b = 1.5x + 240$. A value of 0 means the RSSI is not known. For example, if $x = -68$ dBm, then the encoded value in the route whisker would be $b = 138$. This byte only exists for past hops. Future hops do not have an RSSI value, and thus the RSSI byte is skipped in the payload.
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
\subsubsection{Examples}

\begin{tabularx}{\textwidth}{|X|l|X|l|}
  \hline
  \textbf{Route} & \textbf{Max \# hops} & \textbf{Whisker Data (Hex)} & \textbf{Should digipeat?} \\
  \hline
  \textcolor{red}{VE1ABC}\~{}\textcolor{olive}{0} \textcolor{orange}{[RSSI -96 dBm]} \break
  \textcolor{blue}{VE2DEF}\~{}\textcolor{violet}{234} \textcolor{gray}{[RSSI -13 dBm]} \break
  \textcolor{brown}{VE3XYZ}\~{}\textcolor{teal}{14} \textcolor{purple}{[RSSI -106 dBm]} & 4 & 04 1C 04 \textcolor{red}{56 45 31 41 42 43} FF \textcolor{olive}{00} \textcolor{orange}{60} \textcolor{blue}{56 45 32 44 45 46} FF \textcolor{violet}{EA} \textcolor{gray}{DC} \textcolor{brown}{56 45 33 58 59 5A} FF \textcolor{teal}{0E} \textcolor{purple}{51} & Yes  \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  \textcolor{red}{VE1ABC}\~{}\textcolor{olive}{0} \textcolor{orange}{[RSSI -96 dBm]} \break
  \textcolor{blue}{VE2DEF}\~{}\textcolor{violet}{234} [Future hop] \break
  \textcolor{brown}{VE3XYZ}\~{}\textcolor{teal}{14} [Future hop] & 4 & 04 1A 04 \textcolor{red}{56 45 31 41 42 43} FF \textcolor{olive}{00} \textcolor{orange}{60} \textcolor{blue}{56 45 32 44 45 46} FD \textcolor{violet}{EA} \textcolor{brown}{56 45 33 58 59 5A} FD \textcolor{teal}{0E} & X \\
  \hline
  VE1ABC\~{}0 [RSSI Unknown] \break [FELINET] \break VE2DEF\~{}234 [RSSI -87 dBm] \break [FELINET] \break VE3XYZ\~{}14 [RSSI -65 dBm] & 3 & 04 1E 03 56 45 31 41 42 43 FF 00 00 FE 56 45 32 44 45 46 FF EA 6E FE 56 45 33 58 59 5A FF 0E 8E & No \\
Stephen D's avatar
Stephen D committed
  \hline
  VE1ABC\~{}0 [RSSI -43 dBm] \break [FELINET] \break [FELINET] & 0 & 04 0C 00 56 45 31 41 42 43 FF 00 B0 FE FE & No \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabularx}

Stephen D's avatar
Stephen D committed
\small X = Only if node matches first future hop

Stephen D's avatar
Stephen D committed
\subsection{Destination}

CATS packets can optionally have one or more destinations. This can be useful for e.g. sending a message to another amateur radio operator, or for communicating with a service. The destination consists of a UTF-8 callsign and an SSID byte. \textbf{A valid CATS packet may contain zero or more destination whiskers.}

The destination whisker also allows requesting an acknowledgement from the station, to confirm that the packet was received successfully. This is specified in the acknowledgement byte. If the byte is 0, no acknowledgement is requested. Otherwise, an acknowledgement ID is specified in the 7 least significant bits. The MSB must be cleared. To acknowledge, a CATS packet must be crafted with a destination of the original station's callsign. The acknowledgement byte must have the same acknowledgement ID, but with the MSB set. The MSB is how acknowledgement requests are differentiated from acknowledgement responses.

\subsubsection{Structure}

\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x05 & Whisker type \\
Stephen D's avatar
Stephen D committed
  \hline
  1 & 1 & $N$ & Whisker length in bytes \\
Stephen D's avatar
Stephen D committed
  \hline
  2 & 1 & & Acknowledgement byte \\
  \hline
  3 & $N - 2$ & & UTF-8 callsign \\
  \hline
Stephen D's avatar
Stephen D committed
  $N + 1$ & 1 & & SSID \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabular}

\subsection{Arbitrary}

The arbitrary whisker is a special type of whisker. Its content is intentionally not understood by the CATS standard. Instead, any content can be encoded. Most stations will ignore this content. This is also useful if the same packet is to be sent multiple times. To prevent de-duplication by receiving nodes, a different arbitrary whisker can be affixed to each one. \textbf{A valid CATS packet may contain zero or more arbitrary whiskers.}

Stephen D's avatar
Stephen D committed
\subsubsection{Structure}

Stephen D's avatar
Stephen D committed
\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x06 & Whisker type \\
Stephen D's avatar
Stephen D committed
  \hline
  1 & 1 & $N$ & Whisker length in bytes \\
Stephen D's avatar
Stephen D committed
  \hline
  2 & $N$ & & Data \\
  \hline
\end{tabular}

\subsection{Simplex}

A CATS station may want to articulate a frequency for voice purposes. This would usually be for transmitting what frequencies the station is monitoring. Each simplex whisker represents a single frequency. \textbf{A valid CATS packet may contain zero or more simplex whiskers.}

\subsubsection{Structure}

{\def\arraystretch{1.3}
\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x07 & Whisker type \\
  \hline
  1 & 1 & 6 & Whisker length in bytes \\
  \hline
  2 & 4 & & Frequency (unsigned integer, Hz) \\
  \hline
Stephen D's avatar
Stephen D committed
  6 & 1 & & Modulation type (See modulation table) \\
Stephen D's avatar
Stephen D committed
  7 & 1 & & Power (unsigned integer, ${4 \over{\text{dBm}}} x$, 255 = unknown) \\
  \hline
\end{tabular}
}

\subsubsection{Modulation Table}

\begin{tabular}{|l|l|}
  \hline
  \textbf{Modulation ID} & \textbf{Modulation type} \\
  \hline
  0 & Unknown/unlisted \\
  \hline
  1 & CATS \\
  \hline
  2 & FM (5.0KHz deviation) \\
  \hline
  3 & AM \\
  \hline
  4 & USB \\
  \hline
  5 & LSB \\
  \hline
  6 & CW \\
  \hline
  7 & FreeDV \\
  \hline
  8 & M17 \\
  \hline
  9 & D-STAR \\
  \hline
  10 & DMR \\
  \hline
  11 & Fusion \\
  \hline
  12 & P25 \\
  \hline
  13 & NFM (2.5KHz deviation) \\
\end{tabular}

\subsection{Repeater}

Stephen D's avatar
Stephen D committed
A CATS station may want to articulate repeater information. For instance, a user may want to transmit the repeaters they are monitoring, or a ham radio club may wish to transmit a list of repeaters for their local area. Hypothetically, a CATS-compliant radio could listen to these repeater whiskers and automatically program them into its own memory. \textbf{A valid CATS packet may contain zero or more repeater whiskers.}

Each repeater whisker represents a single repeater.

\subsubsection{Structure}

{\def\arraystretch{1.3}
\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x08 & Whisker type \\
  \hline
  1 & 1 & $N$ & Whisker length in bytes \\
  \hline
  2 & 4 & & Uplink frequency (unsigned integer, Hz) \\
  \hline
  6 & 4 & & Downlink frequency (unsigned integer, Hz) \\
  \hline
Stephen D's avatar
Stephen D committed
  10 & 1 & & Modulation type (See simplex whisker) \\
Stephen D's avatar
Stephen D committed
  11 & 3 & & Tone information (See tones below) \\
Stephen D's avatar
Stephen D committed
  14 & 1 & & Power (unsigned integer, ${4 \over{\text{dBm}}} x$, 255 = unknown) \\
Stephen D's avatar
Stephen D committed
  15 & 2 & & Latitude (signed integer, ${2^{15} \over 90 \degree}x$) \\
Stephen D's avatar
Stephen D committed
  17 & 2 & & Longitude (signed integer, ${2^{15} \over 180 \degree}x$) \\
Stephen D's avatar
Stephen D committed
  19 & $N - 17$ & & Repeater name (UTF-8) \\
  \hline
\end{tabular}
}

Stephen D's avatar
Stephen D committed
\subsubsection{Tones}

Uplink and downlink tones are encoded in 3 bytes. CTCSS and DCS are both supported. The uplink tone is encoded in the 12 MSBs and the downlink tone is encoded in the 12 LSBs. \newline

\noindent
\begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}
  \hline
  MSB &&&&&&&&&&&&&&&&&&&&&&& LSB \\
  \hline
  23 & 22 & 21 & 20 & 19 & 18 & 17 & 16 & 15 & 14 & 13 & 12 & 11 & 10 & 9 & 8 & 7 & 6 & 5 & 4 & 3 & 2 & 1 & 0 \\
  \hline
  $U_e$ & $U_p$ & \multicolumn{10}{|c|}{$U_v$} & $D_e$ & $D_p$ & \multicolumn{10}{|c|}{$D_v$} \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabular} \\
\newline \noindent
Where:

\begin{itemize}
\item $U_e$ and $D_e$ represent the encoding type (0 for CTCSS, 1 for DCS)
Stephen D's avatar
Stephen D committed
\item $U_p$ and $D_p$ represent the DCS tone polarity
  \begin{itemize}
  \item If the type is CTCSS, this value is unused and must be set to 0
  \item If the type is DCS, then
    \begin{itemize}
    \item If the polarity is normal, this value is set to 0
    \item If the polarity is reversed, this value is set to 1
    \end{itemize}
  \end{itemize}
Stephen D's avatar
Stephen D committed
\item $U_v$ and $D_v$ represent the tone value
  \begin{itemize}
  \item If the type is CTCSS, the value is an unsigned integer from the CTCSS table (see below)
  \item If the type is DCS, the value is the DCS code, encoded as an unsigned integer
  \item To encode no tone, set the type to CTCSS (0) and set the value to 0
  \end{itemize}
\end{itemize}

\subsubsection{CTCSS Table}

\begin{tabular}{|l|l|l|l|l|l|l|l|}
  \hline
  \textbf{Tone ID} & \textbf{PL tone (Hz)} & & \textbf{Tone ID} & \textbf{PL tone (Hz)} & & \textbf{Tone ID} & \textbf{PL tone (Hz)} \\
  \hline
  0 & [No tone] & & & & & & \\
  \hline
Stephen D's avatar
Stephen D committed
  1 & 67.0 & & 15 & 107.2 & & 29 & 173.8 \\
Stephen D's avatar
Stephen D committed
  2 & 69.3 & & 16 & 110.9 & & 30 & 179.9 \\
Stephen D's avatar
Stephen D committed
  3 & 71.9 & & 17 & 114.8 & & 31 & 186.2 \\
Stephen D's avatar
Stephen D committed
  4 & 74.4 & & 18 & 118.8 & & 32 & 192.8 \\
Stephen D's avatar
Stephen D committed
  5 & 77.0 & & 19 & 123.0 & & 33 & 203.5 \\
Stephen D's avatar
Stephen D committed
  6 & 79.7 & & 20 & 127.3 & & 34 & 206.5 \\
Stephen D's avatar
Stephen D committed
  7 & 82.5 & & 21 & 131.8 & & 35 & 210.7 \\
Stephen D's avatar
Stephen D committed
  8 & 85.4 & & 22 & 136.5 & & 36 & 218.1 \\
Stephen D's avatar
Stephen D committed
  9 & 88.5 & & 23 & 141.3 & & 37 & 225.7 \\
Stephen D's avatar
Stephen D committed
  10 & 91.5 & & 24 & 146.2 & & 38 & 229.1 \\
Stephen D's avatar
Stephen D committed
  11 & 94.8 & & 25 & 151.4 & & 39 & 233.6 \\
Stephen D's avatar
Stephen D committed
  12 & 97.4 & & 26 & 156.7 & & 40 & 241.8 \\
Stephen D's avatar
Stephen D committed
  13 & 100.0 & & 27 & 162.2 & & 41 & 250.3 \\
Stephen D's avatar
Stephen D committed
  14 & 103.5 & & 28 & 167.9 & & 42 & 254.1 \\
  \hline
\end{tabular}

Stephen D's avatar
Stephen D committed
\subsection{NodeInfo}

A CATS station may want to communicate information about itself. This may be relatively immutable information, such as the hardware revision of the station. It may also include variable information, such as the station's uptime. The NodeInfo whisker provides a range of variables which the station can choose to populate. The NodeInfo uses a bitmap to select which variables are used. This increases efficiency, as unused variables do not need to be transmitted. \textbf{A valid CATS packet contains a maximum of one NodeInfo whisker.}

Stephen D's avatar
Stephen D committed
\subsubsection{Structure}
Stephen D's avatar
Stephen D committed

\begin{tabular}{|l|l|l|l|}
  \hline
  \textbf{Byte offset} & \textbf{Length} & \textbf{Value} & \textbf{Description} \\
  \hline
  0 & 1 & 0x09 & Whisker type \\
  \hline
  1 & 1 & $N$ & Whisker length in bytes \\
  \hline
  2 & 3 & & Bitmap \\
  \hline
  5 & $N - 3$ & & Data \\
  \hline
\end{tabular}

Stephen D's avatar
Stephen D committed
\subsubsection{Variables}
Stephen D's avatar
Stephen D committed

Below is a table of variables. Each variable has an index, which indicates which bit in the bitmap to set to use the variable. A conversion function is also given, which shows how to convert the given value to the raw value stored in the whisker. Note that the ``Transceiver Temperature'' should be a measurement of some part of the transceiver itself. It should not be used to report air temperature or other meteorological data. \newline

\noindent
\begin{tabular}{|l|l|l|l|l|l|}
  \hline
  \textbf{Index} & \textbf{Name} & \textbf{Length} & \textbf{Data Type} & \textbf{Conversion function} & \textbf{Units} \\
  \hline
  0 & Hardware ID & 2 & u16 & $f(x) = x$ & N/A \\
  \hline
  1 & Software ID & 1 & u8 & $f(x) = x$ & N/A \\
  \hline
  2 & Uptime & 4 & u32 & $f(x) = x$ & seconds \\
  \hline
Stephen D's avatar
Stephen D committed
  3 & Antenna height & 1 & u8 & $f(x) = x$ & meters \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  4 & Antenna gain & 1 & u8 & $f(x) = 4x$ & dBi \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  5 & TX power & 1 & u8 & $f(x) = 4x$ & dBm \\
Stephen D's avatar
Stephen D committed
  \hline
  6 & Voltage & 1 & u8 & $f(x) = 10x$ & volts \\
  \hline
Stephen D's avatar
Stephen D committed
  7 & Transceiver temperature & 1 & i8 & $f(x) = x$ & \degree C \\
Stephen D's avatar
Stephen D committed
  \hline
Stephen D's avatar
Stephen D committed
  8 & Battery charge & 1 & u8 & $f(x) = 2.55x$ & percent \\
Stephen D's avatar
Stephen D committed
  \hline
  9 & Altitude (See below) & 4 & f32 & $f(x)= x$ & meters \\
  \hline
  10 & Balloon (See below) & 0 & N/A & N/A & N/A \\
  \hline
Stephen D's avatar
Stephen D committed
  11 & Ambient temperature & 1 & i8 & $f(x) = x$ & \degree C \\
  \hline
  12 & Ambient relative humidity & 1 & u8 & $f(x) = 2.55x$ & percent \\
  \hline
  13 & Ambient pressure & 2 & u16 & $f(x) = x$ & decapascal (daPa) \\
Stephen D's avatar
Stephen D committed
\end{tabular}

\textbf{Altitude}: Although the GPS whisker contains altitude already, it is only 2 bytes long. For most applications this is sufficient, but some require additional precision. For example, high altitude balloons need precise altitude information for accurate landing predictions. The NodeInfo whisker provides the ability to use a 4 byte float for altitude. If set, the NodeInfo whisker altitude should take precedence over the GPS whisker altitude. However, the GPS altitude should be set as close as possible to the NodeInfo altitude. This allows a system which does not implement the NodeInfo whisker to still have correct altitude information.

\textbf{Balloon}: If set, this packet was emitted by a high altitude balloon. Please only set this bit on an actual balloon payload. Transmitters incorrectly marked as balloons cause additional work, and complications, for downstream users of CATS. If, for some reason, you want a non-balloon to show up as a balloon, instead set the icon to be a balloon in the identification whisker, and leave the balloon bit clear.

Stephen D's avatar
Stephen D committed
\subsubsection{Bitmap}
Stephen D's avatar
Stephen D committed

The NodeInfo whisker contains a 3-byte, or 24-bit, bitmap to keep track of which variables are actually used. The extra bits are intended to allow additional variables in the future. The MSB is assigned the index 23; the LSB is index 0. This corresponds to the variables in the above table.

Stephen D's avatar
Stephen D committed
\subsubsection{Example}
Stephen D's avatar
Stephen D committed

\begin{tabular}{|l|l|}
  \hline
  \textbf{Variables} & \textbf{Whisker Data (Hex)} \\
  \hline
  \makecell{
  Hardware ID: 7408 \\
  Uptime: 98 seconds \\
  TX Power: 30 dBm \\
Stephen D's avatar
Stephen D committed
  Voltage: 12.8 V} & 09 0B 00 00 65 F0 1C 62 00 00 00 78 80 \\
Stephen D's avatar
Stephen D committed
  \hline
\end{tabular}

Stephen D's avatar
Stephen D committed
\section{FELINET}

\subsection{Introduction}

Stephen D's avatar
Stephen D committed
FELINET is the Internet counterpart of the CATS standard. Internet gates are responsible for sending received packets to FELINET. Packets received over FELINET can be gated back to RF. Although not part of the standard, it is possible for gateways to move packets between FELINET and APRS-IS. Not all CATS packets can be represented in APRS, so it is preferable to use FELINET when possible.

FELINET is composed of one or more servers. Each server has a list zero or more upstream servers, which it forwards received CATS packets to. Downstream servers request packets from the upstream servers over the same link. Internet gates, or IGates, connect to servers in the same fashion. From the perspective of an upstream server, there is no difference between an IGate and a downstream server.

A FELINET server must discard any received packets that are bitwise identical to any packets it has seen in the previous 10 seconds. This prevents unintentional loops from repeating packets indefinitely and bogging down the network.

To prepare raw data for FELINET, it must go through the Whiskers and CRC section of The Pipeline. In other words, CATS packets are gated to the FELINET network before the Whitener section of The Pipeline. A CATS packet in this binary form is referred to as a ``semi-encoded CATS packet''. It is only ``semi-encoded'' because it does not pass through the end stages of The Pipeline.
Stephen D's avatar
Stephen D committed

\subsection{gRPC}

FELINET nodes communicate with each other via gRPC. A FELINET server implements a $PushPackets$ method, for streaming packets to the server, and a $GetPackets$ method, for streaming packets from the server. The Proto file which defines the FELINET interface is as follows:

\lstinputlisting[language=C]{proto/felinet.proto}

\noindent There are a few points of note to clarify.
\begin{itemize}
Stephen D's avatar
Stephen D committed
\item In $PacketIn.raw$ and $PacketOut.raw$, the value is a semi-encoded CATS packet.
\item In $PacketFilter.filter$, a value must be specified.
Stephen D's avatar
Stephen D committed
\item In $PacketFilter.filter.all$, the value given must be ignored. Protobuf does not have a null type, so a uint32 is used. Again, this value does not signify anything, so a compliant FELINET server must ignore it.
\item In $DistanceFilter.distance$, the unit is meters.
\item In $CallsignFilter.ssid$, the valid values are 0-255, like in all other SSIDs. Protobuf does not have a fixed single-byte type, so a uint32 is used instead. If an invalid value is supplied, the server must reject it, and close the stream.
Stephen D's avatar
Stephen D committed
\end{itemize}
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
\subsection{State}

FELINET servers require some amount of state tracking. This is done by passing a V4 UUID into every request. The client is responsible for generating this UUID.

Stephen D's avatar
Stephen D committed
\subsection{Authentication}

Stephen D's avatar
Stephen D committed
FELINET defines a $Login$ endpoint, which is meant to be used for authentication. The exact usage of this endpoint is up to the server. For example, it may be used to allow any access, it may be used to allow write access, or it may not be used at all. This endpoint is meant to be as flexible as possible.
Stephen D's avatar
Stephen D committed
\subsection{Filtering}
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
When a FELINET node calls the $GetPackets$ method, it must specify an array of filters, which are used to limit what packets are sent to the node from the server. This is done primarily for bandwidth reasons. As such, the filters are very coarse. It is the node's responsibility to filter more on the client-side if required. There are several types of packet filters. When multiple filters are specified, packets which match any filters will be passed to the node. The filter types are as follows:
Stephen D's avatar
Stephen D committed

Stephen D's avatar
Stephen D committed
\begin{description}
\item [All] No filter. All valid packets the server receives will be forwarded to the node.
\item [Distance] Return only packets containing a GPS whisker within the specified latitude (degrees), longitude (degrees), and distance (meters).
\item [Callsign] Return only packets containing the specified callsign/SSID pair. This pair can appear in an identification whisker, route whisker, or destination whisker.
\item [Heard] Return only packets containing a destination or future hop that has been reported to the FELINET server by us in the last $n$ seconds. The value $n$ is specified in the filter. For example, if we send a packet to FELINET with a destination callsign/SSID pair of (ABCXYZ, 6), and less than $n$ seconds later, FELINET receives a packet with (ABCXYZ, 6) as a destination, that packet will be sent to us.
Stephen D's avatar
Stephen D committed
\end{description}
Stephen D's avatar
Stephen D committed

\subsection{Pings}

When a UUID is not used for a period of time, the FELINET server may choose to deallocate its corresponding state. This can be problematic for services that open a connection to FELINET but only send or receive data sparingly. The solution is the $Ping$ endpoint. This endpoint allows ``refreshing'' a UUID, and should be called every 10 minutes for as long as the UUID is used.

Stephen D's avatar
Stephen D committed
\end{document}