GNU Radio's M17 Package
m17.h
Go to the documentation of this file.
1//--------------------------------------------------------------------
2// M17 C library - m17.h
3//
4// Wojciech Kaczmarski, SP5WWP
5// M17 Foundation, 19 April 2025
6//--------------------------------------------------------------------
7#pragma once
8
9#ifdef __cplusplus
10extern "C" {
11#endif
12#include <stdint.h>
13#include <stddef.h>
14#include <string.h>
15#include <time.h>
16#include <math.h>
17
18#define LIBM17_VERSION "1.0.9"
19
20// M17 C library - syncword, payload, and frame sizes in symbols
21#define SYM_PER_SWD 8 //symbols per syncword
22#define SYM_PER_PLD 184 //symbols per payload in a frame
23#define SYM_PER_FRA 192 //symbols per whole 40 ms frame
24
25// Link Setup Frame TYPE definitions
26#define M17_TYPE_PACKET 0
27#define M17_TYPE_STREAM 1
28#define M17_TYPE_DATA (1<<1)
29#define M17_TYPE_VOICE (2<<1)
30#define M17_TYPE_ENCR_NONE (0<<3)
31#define M17_TYPE_ENCR_SCRAM (1<<3)
32#define M17_TYPE_ENCR_AES (2<<3)
33#define M17_TYPE_ENCR_SCRAM_8 (0<<5)
34#define M17_TYPE_ENCR_SCRAM_16 (1<<5)
35#define M17_TYPE_ENCR_SCRAM_24 (2<<5)
36#define M17_TYPE_ENCR_AES128 (0<<5)
37#define M17_TYPE_ENCR_AES192 (1<<5)
38#define M17_TYPE_ENCR_AES256 (2<<5)
39#define M17_TYPE_CAN(x) (x<<7)
40#define M17_TYPE_UNSIGNED (0<<11)
41#define M17_TYPE_SIGNED (1<<11)
42// When no encryption is used, the Encryption Subtype field describes META field contents.
43#define M17_TYPE_META_TEXT (0<<5) //text data
44#define M17_TYPE_META_POSITION (1<<5) //GNSS position data
45#define M17_TYPE_META_EXT_CALL (2<<5) //Extended Callsign data
46
47// LSF META position data
48// LSF META sources
49#define M17_META_SOURCE_M17C 0
50#define M17_META_SOURCE_OPENRTX 1
51#define M17_META_SOURCE_OTHER 255
52#define M17_META_SOURCE_M17C 0
53// LSF META station types
54#define M17_META_STATION_FIXED 0
55#define M17_META_STATION_MOBILE 1
56#define M17_META_STATION_HANDHELD 2
57// LSF META flags
58#define M17_META_LAT_NORTH (0<<0)
59#define M17_META_LAT_SOUTH (1<<0)
60#define M17_META_LON_EAST (0<<1)
61#define M17_META_LON_WEST (1<<1)
62#define M17_META_ALT_DATA_INVALID (0<<2)
63#define M17_META_ALT_DATA_VALID (1<<2)
64#define M17_META_SPD_BEARING_INVALID (0<<3)
65#define M17_META_SPD_BEARING_VALID (1<<3)
66
67// M17 C library - preamble
68/**
69 * @brief Preamble type (0 for LSF, 1 for BERT).
70 */
71typedef enum
72{
75} pream_t;
76
77// M17 C library - frame type
78/**
79 * @brief Frame type (0 - LSF, 1 - stream, 2 - packet, 3 - BERT).
80 */
88
89// M17 C library - payload
90/**
91 * @brief Structure holding Link Setup Frame data.
92 */
93typedef struct
94{
95 uint8_t dst[6];
96 uint8_t src[6];
97 uint8_t type[2];
98 uint8_t meta[112/8];
99 uint8_t crc[2];
100} lsf_t;
101
102// M17 C library - high level functions - m17.c
103void gen_preamble(float out[SYM_PER_FRA], uint32_t* cnt, pream_t type);
104void gen_preamble_i8(int8_t out[SYM_PER_FRA], uint32_t* cnt, pream_t type);
105void gen_syncword(float out[SYM_PER_SWD], uint32_t* cnt, uint16_t syncword);
106void gen_syncword_i8(int8_t out[SYM_PER_SWD], uint32_t* cnt, uint16_t syncword);
107void gen_data(float out[SYM_PER_PLD], uint32_t* cnt, const uint8_t* in);
108void gen_data_i8(int8_t out[SYM_PER_PLD], uint32_t* cnt, const uint8_t* in);
109void gen_eot(float out[SYM_PER_FRA], uint32_t* cnt);
110void gen_eot_i8(int8_t out[SYM_PER_FRA], uint32_t* cnt);
111void gen_frame(float out[SYM_PER_FRA], const uint8_t* data, frame_t type, const lsf_t* lsf, uint8_t lich_cnt, uint16_t fn);
112void gen_frame_i8(int8_t out[SYM_PER_FRA], const uint8_t* data, frame_t type, const lsf_t* lsf, uint8_t lich_cnt, uint16_t fn);
113
114uint32_t decode_LSF(lsf_t* lsf, const float pld_symbs[SYM_PER_PLD]);
115uint32_t decode_str_frame(uint8_t frame_data[16], uint8_t lich[5], uint16_t* fn, uint8_t* lich_cnt, const float pld_symbs[SYM_PER_PLD]);
116uint32_t decode_pkt_frame(uint8_t frame_data[25], uint8_t* eof, uint8_t* fn, const float pld_symbs[SYM_PER_PLD]);
117
118// M17 C library - encode/convol.c
119extern const uint8_t puncture_pattern_1[61];
120extern const uint8_t puncture_pattern_2[12];
121extern const uint8_t puncture_pattern_3[8];
122
123void conv_encode_stream_frame(uint8_t* out, const uint8_t* in, uint16_t fn);
124void conv_encode_packet_frame(uint8_t out[SYM_PER_PLD*2], const uint8_t in[26]);
125void conv_encode_LSF(uint8_t out[SYM_PER_PLD*2], const lsf_t* in);
126void conv_encode_bert_frame(uint8_t out[SYM_PER_PLD*2], const uint8_t in[25]);
127
128// M17 C library - payload/call.c
129#define CHAR_MAP " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
130#define U40_9 (262144000000000ULL) //40^9
131#define U40_9_8 (268697600000000ULL) //40^9+40^8
132
133void decode_callsign_bytes(uint8_t *outp, const uint8_t inp[6]);
134void decode_callsign_value(uint8_t *outp, uint64_t inp);
135int8_t encode_callsign_bytes(uint8_t out[6], const uint8_t *inp);
136int8_t encode_callsign_value(uint64_t *out, const uint8_t *inp);
137
138// M17 C library - payload/crc.c
139//M17 CRC polynomial
140extern const uint16_t M17_CRC_POLY;
141
142uint16_t CRC_M17(const uint8_t* in, uint16_t len);
143uint16_t LSF_CRC(const lsf_t* in);
144
145// M17 C library - payload/lich.c
146void extract_LICH(uint8_t outp[6], uint8_t cnt, const lsf_t* inp);
147void unpack_LICH(uint8_t* out, const uint8_t in[12]);
148
149// M17 C library - payload/lsf.c
151void set_LSF(lsf_t *lsf, char *src, char *dst, uint16_t type, uint8_t meta[14]);
152void set_LSF_meta(lsf_t *lsf, const uint8_t meta[14]);
153void set_LSF_meta_position(lsf_t *lsf, uint8_t data_source, uint8_t station_type,
154 float lat, float lon, uint8_t flags, int32_t altitude, uint16_t bearing, uint8_t speed);
155void set_LSF_meta_ecd(lsf_t *lsf, const char *cf1, const char *cf2);
156void set_LSF_meta_nonce(lsf_t *lsf, time_t ts, const uint8_t rand[10]);
157int8_t get_LSF_meta_position(uint8_t *data_source, uint8_t *station_type,
158 float *lat, float *lon, uint8_t *flags, int32_t *altitude, uint16_t *bearing, uint8_t *speed, const lsf_t *lsf);
159
160// M17 C library - math/golay.c
161extern const uint16_t encode_matrix[12];
162extern const uint16_t decode_matrix[12];
163
164uint32_t golay24_encode(uint16_t data);
165uint16_t golay24_sdecode(const uint16_t codeword[24]);
166void decode_LICH(uint8_t outp[6], const uint16_t inp[96]);
167void encode_LICH(uint8_t outp[12], const uint8_t inp[6]);
168
169// M17 C library - phy/interleave.c
170//interleaver pattern
171extern const uint16_t intrl_seq[SYM_PER_PLD*2];
172
173void reorder_bits(uint8_t outp[SYM_PER_PLD*2], const uint8_t inp[SYM_PER_PLD*2]);
174void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2]);
175
176// M17 C library - math/math.c
177uint16_t q_abs_diff(uint16_t v1, uint16_t v2);
178float eucl_norm(const float* in1, const int8_t* in2, uint8_t n);
179void int_to_soft(uint16_t* out, uint16_t in, uint8_t len);
180uint16_t soft_to_int(const uint16_t* in, uint8_t len);
181uint16_t div16(uint16_t a, uint16_t b);
182uint16_t mul16(uint16_t a, uint16_t b);
183uint16_t soft_bit_XOR(uint16_t a, uint16_t b);
184uint16_t soft_bit_NOT(uint16_t a);
185void soft_XOR(uint16_t* out, const uint16_t* a, const uint16_t* b, uint8_t len);
186
187// M17 C library - phy/randomize.c
188//randomizing pattern
189extern const uint8_t rand_seq[46];
190
191void randomize_bits(uint8_t inp[SYM_PER_PLD*2]);
192void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2]);
193
194// M17 C library - phy/slice.c
195void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD]);
196
197// M17 C library - math/rrc.c
198//sample RRC filter for 48kHz sample rate
199//alpha=0.5, span=8, sps=10, gain=sqrt(sps)
200extern const float rrc_taps_10[8*10+1];
201
202//sample RRC filter for 24kHz sample rate
203//alpha=0.5, span=8, sps=5, gain=sqrt(sps)
204extern const float rrc_taps_5[8*5+1];
205
206// M17 C library - encode/symbols.c
207// dibits-symbols map (TX)
208extern const int8_t symbol_map[4];
209extern const int8_t symbol_list[4];
210
211// M17 C library - phy/sync.c
212//syncwords
213extern const uint16_t SYNC_LSF;
214extern const uint16_t SYNC_STR;
215extern const uint16_t SYNC_PKT;
216extern const uint16_t SYNC_BER;
217extern const uint16_t EOT_MRKR;
218
219// M17 C library - decode/viterbi.c
220#define M17_CONVOL_K 5 //constraint length K=5
221#define M17_CONVOL_STATES (1 << (M17_CONVOL_K - 1)) //number of states of the convolutional encoder
222
223uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, uint16_t len);
224uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, uint16_t in_len, uint16_t p_len);
225void viterbi_decode_bit(uint16_t s0, uint16_t s1, size_t pos);
226uint32_t viterbi_chainback(uint8_t* out, size_t pos, uint16_t len);
227void viterbi_reset(void);
228
229//End of Transmission symbol pattern
230extern const int8_t eot_symbols[8];
231
232// M17 C library - decode/symbols.c
233// syncword patterns (RX)
234// TODO: Compute those at runtime from the consts below
235extern const int8_t lsf_sync_symbols[8];
236extern const int8_t str_sync_symbols[8];
237extern const int8_t pkt_sync_symbols[8];
238
239#ifdef __cplusplus
240}
241#endif
void gen_data_i8(int8_t out[SYM_PER_PLD], uint32_t *cnt, const uint8_t *in)
void conv_encode_packet_frame(uint8_t out[SYM_PER_PLD *2], const uint8_t in[26])
const int8_t eot_symbols[8]
void gen_syncword_i8(int8_t out[SYM_PER_SWD], uint32_t *cnt, uint16_t syncword)
void set_LSF_meta(lsf_t *lsf, const uint8_t meta[14])
uint32_t viterbi_decode(uint8_t *out, const uint16_t *in, uint16_t len)
const uint16_t SYNC_BER
const uint16_t intrl_seq[SYM_PER_PLD *2]
const uint16_t SYNC_PKT
const int8_t symbol_map[4]
uint16_t CRC_M17(const uint8_t *in, uint16_t len)
uint16_t soft_bit_XOR(uint16_t a, uint16_t b)
const uint8_t rand_seq[46]
void unpack_LICH(uint8_t *out, const uint8_t in[12])
uint16_t soft_to_int(const uint16_t *in, uint8_t len)
void set_LSF_meta_position(lsf_t *lsf, uint8_t data_source, uint8_t station_type, float lat, float lon, uint8_t flags, int32_t altitude, uint16_t bearing, uint8_t speed)
void gen_syncword(float out[SYM_PER_SWD], uint32_t *cnt, uint16_t syncword)
const uint16_t M17_CRC_POLY
const uint8_t puncture_pattern_2[12]
void gen_data(float out[SYM_PER_PLD], uint32_t *cnt, const uint8_t *in)
const int8_t lsf_sync_symbols[8]
uint32_t decode_pkt_frame(uint8_t frame_data[25], uint8_t *eof, uint8_t *fn, const float pld_symbs[SYM_PER_PLD])
int8_t encode_callsign_bytes(uint8_t out[6], const uint8_t *inp)
uint16_t LSF_CRC(const lsf_t *in)
uint16_t golay24_sdecode(const uint16_t codeword[24])
const float rrc_taps_5[8 *5+1]
#define SYM_PER_SWD
Definition m17.h:21
int8_t encode_callsign_value(uint64_t *out, const uint8_t *inp)
const int8_t str_sync_symbols[8]
const uint16_t SYNC_STR
#define SYM_PER_FRA
Definition m17.h:23
const int8_t pkt_sync_symbols[8]
void conv_encode_LSF(uint8_t out[SYM_PER_PLD *2], const lsf_t *in)
uint32_t viterbi_decode_punctured(uint8_t *out, const uint16_t *in, const uint8_t *punct, uint16_t in_len, uint16_t p_len)
float eucl_norm(const float *in1, const int8_t *in2, uint8_t n)
void conv_encode_bert_frame(uint8_t out[SYM_PER_PLD *2], const uint8_t in[25])
const uint8_t puncture_pattern_3[8]
void gen_preamble(float out[SYM_PER_FRA], uint32_t *cnt, pream_t type)
uint32_t golay24_encode(uint16_t data)
void viterbi_reset(void)
int8_t get_LSF_meta_position(uint8_t *data_source, uint8_t *station_type, float *lat, float *lon, uint8_t *flags, int32_t *altitude, uint16_t *bearing, uint8_t *speed, const lsf_t *lsf)
const uint16_t encode_matrix[12]
uint16_t q_abs_diff(uint16_t v1, uint16_t v2)
void encode_LICH(uint8_t outp[12], const uint8_t inp[6])
void conv_encode_stream_frame(uint8_t *out, const uint8_t *in, uint16_t fn)
void set_LSF(lsf_t *lsf, char *src, char *dst, uint16_t type, uint8_t meta[14])
void reorder_bits(uint8_t outp[SYM_PER_PLD *2], const uint8_t inp[SYM_PER_PLD *2])
frame_t
Frame type (0 - LSF, 1 - stream, 2 - packet, 3 - BERT).
Definition m17.h:82
@ FRAME_BERT
Definition m17.h:86
@ FRAME_LSF
Definition m17.h:83
@ FRAME_STR
Definition m17.h:84
@ FRAME_PKT
Definition m17.h:85
const uint16_t SYNC_LSF
const float rrc_taps_10[8 *10+1]
uint32_t decode_str_frame(uint8_t frame_data[16], uint8_t lich[5], uint16_t *fn, uint8_t *lich_cnt, const float pld_symbs[SYM_PER_PLD])
void gen_frame(float out[SYM_PER_FRA], const uint8_t *data, frame_t type, const lsf_t *lsf, uint8_t lich_cnt, uint16_t fn)
const uint16_t decode_matrix[12]
uint32_t decode_LSF(lsf_t *lsf, const float pld_symbs[SYM_PER_PLD])
pream_t
Preamble type (0 for LSF, 1 for BERT).
Definition m17.h:72
@ PREAM_BERT
Definition m17.h:74
@ PREAM_LSF
Definition m17.h:73
uint16_t soft_bit_NOT(uint16_t a)
uint16_t mul16(uint16_t a, uint16_t b)
void gen_preamble_i8(int8_t out[SYM_PER_FRA], uint32_t *cnt, pream_t type)
void update_LSF_CRC(lsf_t *lsf)
void reorder_soft_bits(uint16_t outp[SYM_PER_PLD *2], const uint16_t inp[SYM_PER_PLD *2])
void soft_XOR(uint16_t *out, const uint16_t *a, const uint16_t *b, uint8_t len)
void viterbi_decode_bit(uint16_t s0, uint16_t s1, size_t pos)
void gen_eot(float out[SYM_PER_FRA], uint32_t *cnt)
const int8_t symbol_list[4]
void slice_symbols(uint16_t out[2 *SYM_PER_PLD], const float inp[SYM_PER_PLD])
void randomize_soft_bits(uint16_t inp[SYM_PER_PLD *2])
void gen_frame_i8(int8_t out[SYM_PER_FRA], const uint8_t *data, frame_t type, const lsf_t *lsf, uint8_t lich_cnt, uint16_t fn)
void randomize_bits(uint8_t inp[SYM_PER_PLD *2])
void decode_callsign_bytes(uint8_t *outp, const uint8_t inp[6])
void decode_LICH(uint8_t outp[6], const uint16_t inp[96])
void gen_eot_i8(int8_t out[SYM_PER_FRA], uint32_t *cnt)
void int_to_soft(uint16_t *out, uint16_t in, uint8_t len)
const uint8_t puncture_pattern_1[61]
uint16_t div16(uint16_t a, uint16_t b)
uint32_t viterbi_chainback(uint8_t *out, size_t pos, uint16_t len)
const uint16_t EOT_MRKR
void set_LSF_meta_nonce(lsf_t *lsf, time_t ts, const uint8_t rand[10])
void extract_LICH(uint8_t outp[6], uint8_t cnt, const lsf_t *inp)
#define SYM_PER_PLD
Definition m17.h:22
void decode_callsign_value(uint8_t *outp, uint64_t inp)
void set_LSF_meta_ecd(lsf_t *lsf, const char *cf1, const char *cf2)
Structure holding Link Setup Frame data.
Definition m17.h:94
uint8_t dst[6]
Definition m17.h:95
uint8_t src[6]
Definition m17.h:96
uint8_t crc[2]
Definition m17.h:99
uint8_t meta[112/8]
Definition m17.h:98
uint8_t type[2]
Definition m17.h:97