Add files via upload

pull/1/head
Wojciech Kaczmarski 2022-12-07 17:51:28 +01:00 zatwierdzone przez GitHub
rodzic 2a7484fef2
commit b0c9e568d5
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
10 zmienionych plików z 1716 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,271 @@
options:
parameters:
author: SP5WWP
catch_exceptions: 'True'
category: '[GRC Hier Blocks]'
cmake_opt: ''
comment: ''
copyright: M17 Project, Dec 2022
description: ''
gen_cmake: 'On'
gen_linking: dynamic
generate_options: qt_gui
hier_block_src_path: '.:'
id: m17_streamer
max_nouts: '0'
output_language: python
placement: (0,0)
qt_qss_theme: ''
realtime_scheduling: ''
run: 'True'
run_command: '{python} -u {filename}'
run_options: prompt
sizing_mode: fixed
thread_safe_setters: ''
title: M17 data streamer
window_size: (1000,1000)
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [520, 12.0]
rotation: 0
state: enabled
blocks:
- name: blocks_file_sink_0
id: blocks_file_sink
parameters:
affinity: ''
alias: ''
append: 'False'
comment: ''
file: ../stream_fifo
type: byte
unbuffered: 'False'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [680, 172.0]
rotation: 0
state: true
- name: blocks_stream_mux_0
id: blocks_stream_mux
parameters:
affinity: ''
alias: ''
comment: ''
lengths: (6, 6, 2, 14, 16)
maxoutbuf: '0'
minoutbuf: '0'
num_inputs: '5'
type: byte
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [360, 128.0]
rotation: 0
state: enabled
- name: blocks_throttle_0
id: blocks_throttle
parameters:
affinity: ''
alias: ''
comment: ''
ignoretag: 'True'
maxoutbuf: '0'
minoutbuf: '0'
samples_per_second: (6+6+2+14+16)*8*(1000/40)
type: byte
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [528, 188.0]
rotation: 0
state: enabled
- name: blocks_vector_source_x_0
id: blocks_vector_source_x
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
repeat: 'True'
tags: '[]'
type: byte
vector: (0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [112, 12.0]
rotation: 0
state: true
- name: blocks_vector_source_x_0_0
id: blocks_vector_source_x
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
repeat: 'True'
tags: '[]'
type: byte
vector: (0x00, 0x00, 0x1F, 0x24, 0x5D, 0x51)
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [112, 92.0]
rotation: 0
state: true
- name: blocks_vector_source_x_0_1
id: blocks_vector_source_x
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
repeat: 'True'
tags: '[]'
type: byte
vector: (0x00, 0x05)
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [112, 172.0]
rotation: 0
state: true
- name: blocks_vector_source_x_0_2
id: blocks_vector_source_x
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
repeat: 'True'
tags: '[]'
type: byte
vector: (0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00)
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [112, 332.0]
rotation: 0
state: true
- name: blocks_vector_source_x_0_2_0
id: blocks_vector_source_x
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
repeat: 'True'
tags: '[]'
type: byte
vector: (0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00)
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [112, 252.0]
rotation: 0
state: true
- name: note_0
id: note
parameters:
alias: ''
comment: ''
note: DST
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [16, 28.0]
rotation: 0
state: true
- name: note_0_0
id: note
parameters:
alias: ''
comment: ''
note: SRC
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [16, 108.0]
rotation: 0
state: true
- name: note_0_1
id: note
parameters:
alias: ''
comment: ''
note: TYPE
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [16, 188.0]
rotation: 0
state: true
- name: note_0_2
id: note
parameters:
alias: ''
comment: ''
note: DATA
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [16, 348.0]
rotation: 0
state: true
- name: note_0_2_0
id: note
parameters:
alias: ''
comment: ''
note: META
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [16, 268.0]
rotation: 0
state: true
connections:
- [blocks_stream_mux_0, '0', blocks_throttle_0, '0']
- [blocks_throttle_0, '0', blocks_file_sink_0, '0']
- [blocks_vector_source_x_0, '0', blocks_stream_mux_0, '0']
- [blocks_vector_source_x_0_0, '0', blocks_stream_mux_0, '1']
- [blocks_vector_source_x_0_1, '0', blocks_stream_mux_0, '2']
- [blocks_vector_source_x_0_2, '0', blocks_stream_mux_0, '4']
- [blocks_vector_source_x_0_2_0, '0', blocks_stream_mux_0, '3']
metadata:
file_format: 1
grc_version: 3.10.4.0

Wyświetl plik

@ -0,0 +1,511 @@
options:
parameters:
author: SP5WWP
catch_exceptions: 'True'
category: '[GRC Hier Blocks]'
cmake_opt: ''
comment: ''
copyright: M17 Project, Dec 2022
description: ''
gen_cmake: 'On'
gen_linking: dynamic
generate_options: qt_gui
hier_block_src_path: '.:'
id: symbol_recovery
max_nouts: '0'
output_language: python
placement: (0,0)
qt_qss_theme: ''
realtime_scheduling: ''
run: 'True'
run_command: '{python} -u {filename}'
run_options: prompt
sizing_mode: fixed
thread_safe_setters: ''
title: M17 symbol recovery and sync
window_size: (1000,1000)
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [8, 8]
rotation: 0
state: enabled
blocks:
- name: symbol_rate
id: variable
parameters:
comment: ''
value: '4800'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [184, 12]
rotation: 0
state: enabled
- name: analog_quadrature_demod_cf_0
id: analog_quadrature_demod_cf
parameters:
affinity: ''
alias: ''
comment: ''
gain: 24000/(2*math.pi*800)
maxoutbuf: '0'
minoutbuf: '0'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [392, 388.0]
rotation: 0
state: true
- name: blocks_char_to_float_0
id: blocks_char_to_float
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
scale: '128.0'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [216, 244.0]
rotation: 0
state: disabled
- name: blocks_file_sink_0
id: blocks_file_sink
parameters:
affinity: ''
alias: ''
append: 'False'
comment: ''
file: /home/sp5wwp/Desktop/symb_fifo
type: float
unbuffered: 'True'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1144, 180.0]
rotation: 0
state: enabled
- name: blocks_file_source_0
id: blocks_file_source
parameters:
affinity: ''
alias: ''
begin_tag: pmt.PMT_NIL
comment: ''
file: /dev/ttyUSB0
length: '0'
maxoutbuf: '0'
minoutbuf: '0'
offset: '0'
repeat: 'False'
type: byte
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [16, 212.0]
rotation: 0
state: disabled
- name: blocks_file_source_0_0
id: blocks_file_source
parameters:
affinity: ''
alias: ''
begin_tag: pmt.PMT_NIL
comment: ''
file: debug_null_payload.bin
length: '2200'
maxoutbuf: '0'
minoutbuf: '0'
offset: '0'
repeat: 'False'
type: byte
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [24, 500.0]
rotation: 0
state: disabled
- name: blocks_repack_bits_bb_0
id: blocks_repack_bits_bb
parameters:
affinity: ''
alias: ''
align_output: 'False'
comment: ''
endianness: gr.GR_MSB_FIRST
k: '8'
l: '2'
len_tag_key: '""'
maxoutbuf: '0'
minoutbuf: '0'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [216, 524.0]
rotation: 0
state: disabled
- name: digital_chunks_to_symbols_xx_0
id: digital_chunks_to_symbols_xx
parameters:
affinity: ''
alias: ''
comment: ''
dimension: '1'
in_type: byte
maxoutbuf: '0'
minoutbuf: '0'
num_ports: '1'
out_type: float
symbol_table: (1.0, 3.0, -1.0, -3.0)
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [400, 536.0]
rotation: 0
state: disabled
- name: digital_symbol_sync_xx_0
id: digital_symbol_sync_xx
parameters:
affinity: ''
alias: ''
comment: ''
constellation: digital.constellation_bpsk().base()
damping: '1.0'
loop_bw: '0.05'
max_dev: '1.5'
maxoutbuf: '0'
minoutbuf: '0'
nfilters: '128'
osps: '1'
pfb_mf_taps: '[]'
resamp_type: digital.IR_MMSE_8TAP
sps: '5'
ted_gain: '1.0'
ted_type: digital.TED_GARDNER
type: ff
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [824, 188.0]
rotation: 0
state: enabled
- name: qtgui_eye_sink_x_0
id: qtgui_eye_sink_x
parameters:
affinity: ''
alias: ''
alpha1: '1.0'
alpha10: '1.0'
alpha2: '1.0'
alpha3: '1.0'
alpha4: '1.0'
alpha5: '1.0'
alpha6: '1.0'
alpha7: '1.0'
alpha8: '1.0'
alpha9: '1.0'
autoscale: 'False'
axislabels: 'True'
color1: blue
color10: blue
color2: blue
color3: blue
color4: blue
color5: blue
color6: blue
color7: blue
color8: blue
color9: blue
comment: ''
ctrlpanel: 'False'
entags: 'True'
grid: 'False'
gui_hint: ''
label1: Signal 1
label10: Signal 10
label2: Signal 2
label3: Signal 3
label4: Signal 4
label5: Signal 5
label6: Signal 6
label7: Signal 7
label8: Signal 8
label9: Signal 9
legend: 'True'
marker1: '-1'
marker10: '-1'
marker2: '-1'
marker3: '-1'
marker4: '-1'
marker5: '-1'
marker6: '-1'
marker7: '-1'
marker8: '-1'
marker9: '-1'
nconnections: '1'
samp_per_symbol: '1'
size: 200*1
srate: symbol_rate*1
style1: '1'
style10: '1'
style2: '1'
style3: '1'
style4: '1'
style5: '1'
style6: '1'
style7: '1'
style8: '1'
style9: '1'
tr_chan: '0'
tr_delay: '0'
tr_level: '0.0'
tr_mode: qtgui.TRIG_MODE_FREE
tr_slope: qtgui.TRIG_SLOPE_POS
tr_tag: '""'
type: float
update_time: '0.10'
width1: '1'
width10: '1'
width2: '1'
width3: '1'
width4: '1'
width5: '1'
width6: '1'
width7: '1'
width8: '1'
width9: '1'
ylabel: Amplitude
ymax: '5'
ymin: '-5'
yunit: '""'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1144, 268.0]
rotation: 0
state: enabled
- name: qtgui_time_sink_x_0
id: qtgui_time_sink_x
parameters:
affinity: ''
alias: ''
alpha1: '1.0'
alpha10: '1.0'
alpha2: '1.0'
alpha3: '1.0'
alpha4: '1.0'
alpha5: '1.0'
alpha6: '1.0'
alpha7: '1.0'
alpha8: '1.0'
alpha9: '1.0'
autoscale: 'False'
axislabels: 'True'
color1: blue
color10: dark blue
color2: red
color3: green
color4: black
color5: cyan
color6: magenta
color7: yellow
color8: dark red
color9: dark green
comment: ''
ctrlpanel: 'False'
entags: 'True'
grid: 'False'
gui_hint: ''
label1: Signal 1
label10: Signal 10
label2: Signal 2
label3: Signal 3
label4: Signal 4
label5: Signal 5
label6: Signal 6
label7: Signal 7
label8: Signal 8
label9: Signal 9
legend: 'True'
marker1: '-1'
marker10: '-1'
marker2: '-1'
marker3: '-1'
marker4: '-1'
marker5: '-1'
marker6: '-1'
marker7: '-1'
marker8: '-1'
marker9: '-1'
name: '""'
nconnections: '1'
size: '1024'
srate: symbol_rate*5
stemplot: 'False'
style1: '1'
style10: '1'
style2: '1'
style3: '1'
style4: '1'
style5: '1'
style6: '1'
style7: '1'
style8: '1'
style9: '1'
tr_chan: '0'
tr_delay: '0'
tr_level: '0.0'
tr_mode: qtgui.TRIG_MODE_FREE
tr_slope: qtgui.TRIG_SLOPE_POS
tr_tag: '""'
type: float
update_time: '0.10'
width1: '1'
width10: '1'
width2: '1'
width3: '1'
width4: '1'
width5: '1'
width6: '1'
width7: '1'
width8: '1'
width9: '1'
ylabel: Amplitude
ymax: '5'
ymin: '-5'
yunit: '""'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [824, 100.0]
rotation: 0
state: disabled
- name: rational_resampler_xxx_0
id: rational_resampler_xxx
parameters:
affinity: ''
alias: ''
comment: ''
decim: '80'
fbw: '0'
interp: '1'
maxoutbuf: '0'
minoutbuf: '0'
taps: '[]'
type: ccf
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [224, 364.0]
rotation: 0
state: true
- name: root_raised_cosine_filter_0
id: root_raised_cosine_filter
parameters:
affinity: ''
alias: ''
alpha: '0.5'
comment: ''
decim: '1'
gain: '1'
interp: '1'
maxoutbuf: '0'
minoutbuf: '0'
ntaps: 8*5+1
samp_rate: '5'
sym_rate: '1'
type: fir_filter_fff
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [560, 348.0]
rotation: 0
state: enabled
- name: root_raised_cosine_filter_0_0
id: root_raised_cosine_filter
parameters:
affinity: ''
alias: ''
alpha: '0.5'
comment: ''
decim: '1'
gain: 1/0.12
interp: '1'
maxoutbuf: '0'
minoutbuf: '0'
ntaps: 8*5+1
samp_rate: '5'
sym_rate: '1'
type: fir_filter_fff
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [560, 204.0]
rotation: 0
state: disabled
- name: soapy_rtlsdr_source_0
id: soapy_rtlsdr_source
parameters:
affinity: ''
agc: 'True'
alias: ''
center_freq: '439950000'
comment: ''
dev_args: ''
freq_correction: '-2'
gain: '20'
maxoutbuf: '0'
minoutbuf: '0'
samp_rate: 24000*80
type: fc32
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [24, 380.0]
rotation: 0
state: true
connections:
- [analog_quadrature_demod_cf_0, '0', root_raised_cosine_filter_0, '0']
- [blocks_char_to_float_0, '0', root_raised_cosine_filter_0_0, '0']
- [blocks_file_source_0, '0', blocks_char_to_float_0, '0']
- [blocks_file_source_0_0, '0', blocks_repack_bits_bb_0, '0']
- [blocks_repack_bits_bb_0, '0', digital_chunks_to_symbols_xx_0, '0']
- [digital_chunks_to_symbols_xx_0, '0', blocks_file_sink_0, '0']
- [digital_chunks_to_symbols_xx_0, '0', qtgui_eye_sink_x_0, '0']
- [digital_symbol_sync_xx_0, '0', blocks_file_sink_0, '0']
- [digital_symbol_sync_xx_0, '0', qtgui_eye_sink_x_0, '0']
- [rational_resampler_xxx_0, '0', analog_quadrature_demod_cf_0, '0']
- [root_raised_cosine_filter_0, '0', digital_symbol_sync_xx_0, '0']
- [root_raised_cosine_filter_0, '0', qtgui_time_sink_x_0, '0']
- [root_raised_cosine_filter_0_0, '0', digital_symbol_sync_xx_0, '0']
- [root_raised_cosine_filter_0_0, '0', qtgui_time_sink_x_0, '0']
- [soapy_rtlsdr_source_0, '0', rational_resampler_xxx_0, '0']
metadata:
file_format: 1
grc_version: 3.10.4.0

93
SP5WWP/inc/m17.h 100644
Wyświetl plik

@ -0,0 +1,93 @@
#ifndef M17_CONSTS
#define M17_CONSTS
#define FLT_LEN 81 //baseband filter length (number of taps)
#define SW_LEN 80 //syncword detector length
#define XC_LEN 90 //cross-correlator lookback length in samples
#define SYM_PER_PLD 184 //symbols per payload in a frame
//syncword patterns (RX) TODO:Compute those at runtime from the consts below
const int8_t str_sync[8]={-3, -3, -3, -3, +3, +3, -3, +3};
const int8_t lsf_sync[8]={+3, +3, +3, +3, -3, -3, +3, -3};
//symbol levels (RX)
const float symbs[4]={-3.0, -1.0, +1.0, +3.0};
//dibits-symbols map (TX)
const int8_t symbol_map[4]={+1, +3, -1, -3};
//syncwords
const uint16_t SYNC_LSF = 0x55F7;
const uint16_t SYNC_STR = 0xFF5D;
const uint16_t SYNC_PKT = 0x75FF;
const uint16_t SYNC_BER = 0xDF55;
const uint16_t EOT_MRKR = 0x555D;
//RRC filter - 10 samples per symbol, 8 symbols span
const float taps[FLT_LEN]=
{
-0.003195702904062073, -0.002930279157647190, -0.001940667871554463,
-0.000356087678023658, 0.001547011339077758, 0.003389554791179751,
0.004761898604225673, 0.005310860846138910, 0.004824746306020221,
0.003297923526848786, 0.000958710871218619, -0.001749908029791816,
-0.004238694106631223, -0.005881783042101693, -0.006150256456781309,
-0.004745376707651645, -0.001704189656473565, 0.002547854551539951,
0.007215575568844704, 0.011231038205363532, 0.013421952197060707,
0.012730475385624438, 0.008449554307303753, 0.000436744366018287,
-0.010735380379191660, -0.023726883538258272, -0.036498030780605324,
-0.046500883189991064, -0.050979050575999614, -0.047340680079891187,
-0.033554880492651755, -0.008513823955725943, 0.027696543159614194,
0.073664520037517042, 0.126689053778116234, 0.182990955139333916,
0.238080025892859704, 0.287235637987091563, 0.326040247765297220,
0.350895727088112619, 0.359452932027607974, 0.350895727088112619,
0.326040247765297220, 0.287235637987091563, 0.238080025892859704,
0.182990955139333916, 0.126689053778116234, 0.073664520037517042,
0.027696543159614194, -0.008513823955725943, -0.033554880492651755,
-0.047340680079891187, -0.050979050575999614, -0.046500883189991064,
-0.036498030780605324, -0.023726883538258272, -0.010735380379191660,
0.000436744366018287, 0.008449554307303753, 0.012730475385624438,
0.013421952197060707, 0.011231038205363532, 0.007215575568844704,
0.002547854551539951, -0.001704189656473565, -0.004745376707651645,
-0.006150256456781309, -0.005881783042101693, -0.004238694106631223,
-0.001749908029791816, 0.000958710871218619, 0.003297923526848786,
0.004824746306020221, 0.005310860846138910, 0.004761898604225673,
0.003389554791179751, 0.001547011339077758, -0.000356087678023658,
-0.001940667871554463, -0.002930279157647190, -0.003195702904062073
};
//randomizing pattern
const uint8_t rand_seq[46]=
{
0xD6, 0xB5, 0xE2, 0x30, 0x82, 0xFF, 0x84, 0x62, 0xBA, 0x4E, 0x96, 0x90, 0xD8, 0x98, 0xDD, 0x5D, 0x0C, 0xC8, 0x52, 0x43, 0x91, 0x1D, 0xF8,
0x6E, 0x68, 0x2F, 0x35, 0xDA, 0x14, 0xEA, 0xCD, 0x76, 0x19, 0x8D, 0xD5, 0x80, 0xD1, 0x33, 0x87, 0x13, 0x57, 0x18, 0x2D, 0x29, 0x78, 0xC3
};
//interleaver pattern
const uint16_t intrl_seq[368]=
{
0, 137, 90, 227, 180, 317, 270, 39, 360, 129, 82, 219, 172, 309, 262, 31,
352, 121, 74, 211, 164, 301, 254, 23, 344, 113, 66, 203, 156, 293, 246, 15,
336, 105, 58, 195, 148, 285, 238, 7, 328, 97, 50, 187, 140, 277, 230, 367,
320, 89, 42, 179, 132, 269, 222, 359, 312, 81, 34, 171, 124, 261, 214, 351,
304, 73, 26, 163, 116, 253, 206, 343, 296, 65, 18, 155, 108, 245, 198, 335,
288, 57, 10, 147, 100, 237, 190, 327, 280, 49, 2, 139, 92, 229, 182, 319,
272, 41, 362, 131, 84, 221, 174, 311, 264, 33, 354, 123, 76, 213, 166, 303,
256, 25, 346, 115, 68, 205, 158, 295, 248, 17, 338, 107, 60, 197, 150, 287,
240, 9, 330, 99, 52, 189, 142, 279, 232, 1, 322, 91, 44, 181, 134, 271,
224, 361, 314, 83, 36, 173, 126, 263, 216, 353, 306, 75, 28, 165, 118, 255,
208, 345, 298, 67, 20, 157, 110, 247, 200, 337, 290, 59, 12, 149, 102, 239,
192, 329, 282, 51, 4, 141, 94, 231, 184, 321, 274, 43, 364, 133, 86, 223,
176, 313, 266, 35, 356, 125, 78, 215, 168, 305, 258, 27, 348, 117, 70, 207,
160, 297, 250, 19, 340, 109, 62, 199, 152, 289, 242, 11, 332, 101, 54, 191,
144, 281, 234, 3, 324, 93, 46, 183, 136, 273, 226, 363, 316, 85, 38, 175,
128, 265, 218, 355, 308, 77, 30, 167, 120, 257, 210, 347, 300, 69, 22, 159,
112, 249, 202, 339, 292, 61, 14, 151, 104, 241, 194, 331, 284, 53, 6, 143,
96, 233, 186, 323, 276, 45, 366, 135, 88, 225, 178, 315, 268, 37, 358, 127,
80, 217, 170, 307, 260, 29, 350, 119, 72, 209, 162, 299, 252, 21, 342, 111,
64, 201, 154, 291, 244, 13, 334, 103, 56, 193, 146, 283, 236, 5, 326, 95,
48, 185, 138, 275, 228, 365, 318, 87, 40, 177, 130, 267, 220, 357, 310, 79,
32, 169, 122, 259, 212, 349, 302, 71, 24, 161, 114, 251, 204, 341, 294, 63,
16, 153, 106, 243, 196, 333, 286, 55, 8, 145, 98, 235, 188, 325, 278, 47
};
#endif

Wyświetl plik

@ -0,0 +1,70 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include "../inc/m17.h"
struct LSF
{
uint8_t dst[6];
uint8_t src[6];
uint8_t type[2];
uint8_t meta[112/8];
uint8_t crc[2];
} lsf;
uint8_t data[16];
uint16_t fn=0; //16-bit Frame Number (for the stream mode)
uint8_t got_lsf=0; //have we filled the LSF struct yet?
//main routine
int main(void)
{
while(1)
{
if(got_lsf) //stream frames
{
//we could discard the data we already have
while(read(STDIN_FILENO, &(lsf.dst), 6)<6);
while(read(STDIN_FILENO, &(lsf.src), 6)<6);
while(read(STDIN_FILENO, &(lsf.type), 2)<2);
while(read(STDIN_FILENO, &(lsf.meta), 14)<14);
while(read(STDIN_FILENO, data, 16)<16);
printf("\tDATA: ");
for(uint8_t i=0; i<16; i++)
printf("%02X", data[i]);
printf("\n");
}
else //LSF
{
while(read(STDIN_FILENO, &(lsf.dst), 6)<6);
while(read(STDIN_FILENO, &(lsf.src), 6)<6);
while(read(STDIN_FILENO, &(lsf.type), 2)<2);
while(read(STDIN_FILENO, &(lsf.meta), 14)<14);
while(read(STDIN_FILENO, data, 16)<16);
got_lsf=1;
printf("DST: ");
for(uint8_t i=0; i<6; i++)
printf("%02X", lsf.dst[i]);
printf(" SRC: ");
for(uint8_t i=0; i<6; i++)
printf("%02X", lsf.src[i]);
printf(" TYPE: ");
for(uint8_t i=0; i<2; i++)
printf("%02X", lsf.type[i]);
printf(" META: ");
for(uint8_t i=0; i<14; i++)
printf("%02X", lsf.meta[i]);
printf("\n");
}
}
return 0;
}

Wyświetl plik

@ -0,0 +1,228 @@
#include <string.h>
#include <stdint.h>
#include "golay.h"
const uint16_t encode_matrix[12]=
{
0x8eb, 0x93e, 0xa97, 0xdc6, 0x367, 0x6cd,
0xd99, 0x3da, 0x7b4, 0xf68, 0x63b, 0xc75
};
const uint16_t decode_matrix[12]=
{
0xc75, 0x49f, 0x93e, 0x6e3, 0xdc6, 0xf13,
0xab9, 0x1ed, 0x3da, 0x7b4, 0xf68, 0xa4f
};
//0 index - LSB
void IntToSoft(uint16_t* out, const uint16_t in, uint8_t len)
{
for(uint8_t i=0; i<len; i++)
{
(in>>i)&1 ? (out[i]=0xFFFF) : (out[i]=0);
}
}
uint16_t SoftToInt(const uint16_t* in, uint8_t len)
{
uint16_t tmp=0;
for(uint8_t i=0; i<len; i++)
{
if(in[i]>0x7FFF)
tmp|=(1<<i);
}
return tmp;
}
//Quadrant I fixed point division with saturation
//result=a/b
uint16_t Div16(uint16_t a, uint16_t b)
{
uint32_t aa=a<<16;
uint32_t r=aa/b;
if(r<=0xFFFF)
return r;
else
return 0xFFFF;
}
//Quadrant I fixed point multiplication
//result=a/b
uint16_t Mul16(uint16_t a, uint16_t b)
{
return (uint16_t)(((uint32_t)a*b)>>16);
}
//use bilinear interpolation for XOR
uint16_t SoftBitXOR(const uint16_t a, const uint16_t b)
{
return Mul16(Div16(0xFFFF-b, 0xFFFF), Div16(a, 0xFFFF)) + Mul16(Div16(b, 0xFFFF), Div16(0xFFFF-a, 0xFFFF));
}
//soft XOR
void SoftXOR(uint16_t* out, const uint16_t* a, const uint16_t* b, uint8_t len)
{
for(uint8_t i=0; i<len; i++)
out[i]=SoftBitXOR(a[i], b[i]);
}
//soft equivalent of popcount
uint32_t spopcount(const uint16_t* in, uint8_t siz)
{
uint32_t tmp=0;
for(uint8_t i=0; i<siz; i++)
tmp+=in[i];
return tmp;
}
void calcChecksumS(uint16_t* out, const uint16_t* value)
{
uint16_t checksum[12];
uint16_t soft_em[12]; //soft valued encoded matrix entry
for(uint8_t i=0; i<12; i++)
checksum[i]=0;
for(uint8_t i=0; i<12; i++)
{
IntToSoft(soft_em, encode_matrix[i], 12);
if(value[i]>0x7FFF)
{
SoftXOR(checksum, checksum, soft_em, 12);
}
}
memcpy((uint8_t*)out, (uint8_t*)checksum, 12*2);
}
uint32_t SdetectErrors(const uint16_t* codeword)
{
uint16_t data[12];
uint16_t parity[12];
uint16_t cksum[12];
uint16_t syndrome[12];
uint32_t weight; //for soft popcount
memcpy((uint8_t*)data, (uint8_t*)&codeword[12], 2*12);
memcpy((uint8_t*)parity, (uint8_t*)&codeword[0], 2*12);
calcChecksumS(cksum, data);
SoftXOR(syndrome, parity, cksum, 12);
weight=spopcount(syndrome, 12);
//all (less than 4) errors in the parity part
if(weight < 4*0xFFFE)
{
//printf("1: %1.2f\n", (float)weight/0xFFFF);
return SoftToInt(syndrome, 12);
}
//one of the errors in data part, up to 3 in parity
for(uint8_t i = 0; i<12; i++)
{
uint16_t e = 1<<i;
uint16_t coded_error = encode_matrix[i];
uint16_t scoded_error[12]; //soft coded_error
uint16_t sc[12]; //syndrome^coded_error
IntToSoft(scoded_error, coded_error, 12);
SoftXOR(sc, syndrome, scoded_error, 12);
weight=spopcount(sc, 12);
if(weight < 3*0xFFFE)
{
//printf("2: %1.2f\n", (float)weight/0xFFFF+1);
uint16_t s=SoftToInt(syndrome, 12);
return (e << 12) | (s ^ coded_error);
}
}
//two of the errors in data part and up to 2 in parity
for(uint8_t i = 0; i<11; i++)
{
for(uint8_t j = i+1; j<12; j++)
{
uint16_t e = (1<<i) | (1<<j);
uint16_t coded_error = encode_matrix[i]^encode_matrix[j];
uint16_t scoded_error[12]; //soft coded_error
uint16_t sc[12]; //syndrome^coded_error
IntToSoft(scoded_error, coded_error, 12);
SoftXOR(sc, syndrome, scoded_error, 12);
weight=spopcount(sc, 12);
if(weight < 2*0xFFFF)
{
//printf("3: %1.2f\n", (float)weight/0xFFFF+2);
uint16_t s=SoftToInt(syndrome, 12);
return (e << 12) | (s ^ coded_error);
}
}
}
//algebraic decoding magic
uint16_t inv_syndrome[12]={0,0,0,0,0,0,0,0,0,0,0,0};
uint16_t dm[12]; //soft decode matrix
for(uint8_t i=0; i<12; i++)
{
if(syndrome[i] > 0x7FFF)
{
IntToSoft(dm, decode_matrix[i], 12);
SoftXOR(inv_syndrome, inv_syndrome, dm, 12);
}
}
//all (less than 4) errors in the data part
weight=spopcount(inv_syndrome, 12);
if(weight < 4*0xFFFF)
{
//printf("4: %1.2f\n", (float)weight/0xFFFF);
return SoftToInt(inv_syndrome, 12) << 12;
}
//one error in parity bits, up to 3 in data - this part has some quirks, the reason remains unknown
for(uint8_t i=0; i<12; i++)
{
uint16_t e = 1<<i;
uint16_t coding_error = decode_matrix[i];
uint16_t ce[12]; //soft coding error
uint16_t tmp[12];
IntToSoft(ce, coding_error, 12);
SoftXOR(tmp, inv_syndrome, ce, 12);
weight=spopcount(tmp, 12);
if(weight < 3*(0xFFFF+2))
{
//printf("5: %1.2f\n", (float)weight/0xFFFF+1);
return ((SoftToInt(inv_syndrome, 12) ^ coding_error) << 12) | e;
}
}
return 0xFFFFFFFF;
}
//soft decode
uint16_t golay24_sdecode(const uint16_t* codeword)
{
//match the bit order in M17
uint16_t cw[24];
for(uint8_t i=0; i<24; i++)
cw[i]=codeword[23-i];
uint32_t errors = SdetectErrors(cw);
if(errors == 0xFFFFFFFF)
return 0xFFFF;
return (((SoftToInt(&cw[0], 16) | (SoftToInt(&cw[16], 8) << 16)) ^ errors) >> 12) & 0x0FFF;
}

Wyświetl plik

@ -0,0 +1,15 @@
#ifndef GOLAY_H
#define GOLAY_H
void IntToSoft(uint16_t* out, const uint16_t in, uint8_t len);
uint16_t SoftToInt(const uint16_t* in, uint8_t len);
uint16_t Div16(uint16_t a, uint16_t b);
uint16_t Mul16(uint16_t a, uint16_t b);
uint16_t SoftBitXOR(const uint16_t a, const uint16_t b);
void SoftXOR(uint16_t* out, const uint16_t* a, const uint16_t* b, uint8_t len);
uint32_t spopcount(const uint16_t* in, uint8_t siz);
void calcChecksumS(uint16_t* out, const uint16_t* value);
uint32_t SdetectErrors(const uint16_t* codeword);
uint16_t golay24_sdecode(const uint16_t* codeword);
#endif

Wyświetl plik

@ -0,0 +1,229 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include "../inc/m17.h"
#include "golay.h"
#include "viterbi.h"
float sample; //last raw sample from the stdin
float last[8]; //look-back buffer for finding syncwords
float xcorr; //cross correlation for finding syncwords
float pld[SYM_PER_PLD]; //raw frame symbols
uint16_t soft_bit[2*SYM_PER_PLD]; //raw frame soft bits
uint16_t d_soft_bit[2*SYM_PER_PLD]; //deinterleaved soft bits
uint8_t lsf[30]; //complete LSF
uint16_t lich_chunk[96]; //raw, soft LSF chunk extracted from the LICH
uint8_t lich_b[6]; //48-bit decoded LICH
uint8_t lich_cnt; //LICH_CNT
uint8_t lich_chunks_rcvd=0; //flags set for each LSF chunk received
uint16_t enc_data[272]; //raw frame data soft bits
uint8_t frame_data[19]; //decoded frame data, 144 bits (16+128), plus 4 flushing bits
uint8_t syncd=0; //syncword found?
uint8_t pushed; //counter for pushed symbols
extern const uint8_t P2_pat[12];
//soft decodes LICH into a 6-byte array
//input - soft bits
//output - an array of packed bits
void decode_LICH(uint8_t* outp, const uint16_t* inp)
{
uint16_t tmp;
memset(outp, 0, 5);
tmp=golay24_sdecode(&inp[0]);
outp[0]=(tmp>>4)&0xFF;
outp[1]|=(tmp&0xF)<<4;
tmp=golay24_sdecode(&inp[1*24]);
outp[1]|=(tmp>>8)&0xF;
outp[2]=tmp&0xFF;
tmp=golay24_sdecode(&inp[2*24]);
outp[3]=(tmp>>4)&0xFF;
outp[4]|=(tmp&0xF)<<4;
tmp=golay24_sdecode(&inp[3*24]);
outp[4]|=(tmp>>8)&0xF;
outp[5]=tmp&0xFF;
}
int main(void)
{
while(1)
{
//wait for another symbol
while(read(STDIN_FILENO, (uint8_t*)&sample, 4)<4);
if(!syncd)
{
//push new symbol
for(uint8_t i=0; i<7; i++)
{
last[i]=last[i+1];
}
last[7]=sample;
//calculate cross-correlation
xcorr=0;
for(uint8_t i=0; i<8; i++)
{
xcorr+=last[i]*str_sync[i];
}
//printf("%f\n", xcorr);
if(xcorr>62.0)
{
syncd=1;
pushed=0;
}
else if(xcorr<-62)
{
printf("LSF\n");
}
}
else
{
pld[pushed++]=sample;
if(pushed==SYM_PER_PLD)
{
//decode symbols to soft dibits
for(uint8_t i=0; i<SYM_PER_PLD; i++)
{
//bit 0
if(pld[i]>=symbs[3])
{
soft_bit[i*2+1]=0xFFFF;
}
else if(pld[i]>=symbs[2])
{
soft_bit[i*2+1]=-(float)0xFFFF/(symbs[3]-symbs[2])*symbs[2]+pld[i]*(float)0xFFFF/(symbs[3]-symbs[2]);
}
else if(pld[i]>=symbs[1])
{
soft_bit[i*2+1]=0x0000;
}
else if(pld[i]>=symbs[0])
{
soft_bit[i*2+1]=(float)0xFFFF/(symbs[1]-symbs[0])*symbs[1]-pld[i]*(float)0xFFFF/(symbs[1]-symbs[0]);
}
else
{
soft_bit[i*2+1]=0xFFFF;
}
//bit 1
if(pld[i]>=symbs[2])
{
soft_bit[i*2]=0x0000;
}
else if(pld[i]>=symbs[1])
{
soft_bit[i*2]=0x7FFF-pld[i]*(float)0xFFFF/(symbs[2]-symbs[1]);
}
else
{
soft_bit[i*2]=0xFFFF;
}
}
//derandomize
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
{
if((rand_seq[i/8]>>(7-(i%8)))&1) //soft XOR. flip soft bit if "1"
soft_bit[i]=0xFFFF-soft_bit[i];
}
//deinterleave
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
{
d_soft_bit[i]=soft_bit[intrl_seq[i]];
}
//extract LICH
for(uint16_t i=0; i<96; i++)
{
lich_chunk[i]=d_soft_bit[i];
}
//Golay decoder
decode_LICH(lich_b, lich_chunk);
lich_cnt=lich_b[5]>>5;
lich_chunks_rcvd|=(1<<lich_cnt);
memcpy(&lsf[lich_cnt*5], lich_b, 5);
//debug - dump LICH
if(lich_chunks_rcvd==0x3F)
{
/*//DST
printf("DST: ");
for(uint8_t i=0; i<6; i++)
printf("%02X", lsf[i]);
printf(" ");
//SRC
printf("SRC: ");
for(uint8_t i=0; i<6; i++)
printf("%02X", lsf[6+i]);
printf(" ");
//TYPE
printf("TYPE: ");
for(uint8_t i=0; i<2; i++)
printf("%02X", lsf[12+i]);
printf(" ");
//META
printf("META: ");
for(uint8_t i=0; i<14; i++)
printf("%02X", lsf[14+i]);
printf(" ");
//CRC
printf("CRC: ");
for(uint8_t i=0; i<2; i++)
printf("%02X", lsf[28+i]);
printf("\n");*/
lich_chunks_rcvd=0; //reset all flags
}
//extract data
for(uint16_t i=0; i<272; i++)
{
enc_data[i]=d_soft_bit[96+i];
}
//decode
uint32_t e=decodePunctured(frame_data, enc_data, P2_pat, 272, 12);
//dump data - first byte is empty
/*printf("FN: %02X%02X PLD: ", frame_data[1], frame_data[2]);
for(uint8_t i=3; i<19; i++)
{
printf("%02X", frame_data[i]);
}
printf(" e=%1.1f\n", (float)e/0xFFFF);*/
//send codec2 stream to stdout
//write(STDOUT_FILENO, &frame_data[3], 16);
//job done
syncd=0;
pushed=0;
for(uint8_t i=0; i<8; i++)
last[i]=0.0;
}
}
}
return 0;
}

Wyświetl plik

@ -0,0 +1,72 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include "../inc/m17.h"
int16_t sample; //raw S16_LE baseband sample
int16_t flt_buff[FLT_LEN]; //root-nyquist filter buffer
int16_t sw_buff[SW_LEN]; //syncword detection buffer
int16_t xc_buff[XC_LEN]; //cross-correlation buffer
int16_t mac; //multiply-accumulate
//states
uint8_t pre_syncd=0;
uint8_t syncd=0;
int8_t phase=0;
int main(void)
{
while(1)
{
//wait for another baseband sample
while(read(STDIN_FILENO, (uint8_t*)&sample, 2)<2);
//push the root-nyquist filter's buffer
for(uint8_t i=0; i<FLT_LEN-1; i++)
{
flt_buff[i]=flt_buff[i+1];
}
flt_buff[FLT_LEN-1]=sample;
//calculate the filter's output
mac=0;
for(uint8_t i=0; i<FLT_LEN; i++)
mac+=flt_buff[i]*taps[i];
for(uint8_t i=0; i<FLT_LEN-2; i++)
{
sw_buff[i]=sw_buff[i+1];
}
sw_buff[FLT_LEN-2]=mac;
//detect syncword using cross-correlation
int32_t xcorr=0;
for(uint8_t i=0; i<XC_LEN; i+=10)
{
xcorr+=sw_buff[i]*str_sync[i/10];
}
//push the xcorr value to the buffer
for(uint8_t i=0; i<XC_LEN-1; i++)
{
xc_buff[i]=xc_buff[i+1];
}
xc_buff[XC_LEN-1]=xcorr/24;
//detect peak
if(xc_buff[XC_LEN-1]>0.4*INT16_MAX)
{
uint8_t msg[64];
uint8_t len=sprintf(msg, "SYNC\n");
write(STDERR_FILENO, msg, len);
}
}
return 0;
}

Wyświetl plik

@ -0,0 +1,216 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "viterbi.h"
#define K 5 //constraint length
#define NUM_STATES (1 << (K - 1)) //number of states
const uint8_t P2_pat[12]={1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; //P_2 puncturing pattern for stream frames
//vars
uint32_t prevMetrics[NUM_STATES];
uint32_t currMetrics[NUM_STATES];
uint32_t prevMetricsData[NUM_STATES];
uint32_t currMetricsData[NUM_STATES];
uint16_t history[244];
/**
* Decode unpunctured convolutionally encoded data.
*
* @param out: destination array where decoded data is written.
* @param in: input data.
* @param len: input length in bits
* @return number of bit errors corrected.
*/
uint32_t decode(uint8_t* out, const uint16_t* in, uint16_t len)
{
if(len > 244*2)
fprintf((FILE*)STDERR_FILENO, "Input size exceeds max history\n");
reset();
size_t pos = 0;
for(size_t i = 0; i < len; i += 2)
{
uint16_t s0 = in[i];
uint16_t s1 = in[i + 1];
decodeBit(s0, s1, pos);
pos++;
}
return chainback(out, pos, len/2);
}
/**
* Decode punctured convolutionally encoded data.
*
* @param out: destination array where decoded data is written.
* @param in: input data.
* @param punct: puncturing matrix.
* @param in_len: input data length.
* @param p_len: puncturing matrix length (entries).
* @return number of bit errors corrected.
*/
uint32_t decodePunctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, uint16_t in_len, uint16_t p_len) //input length, puncturing pattern length
{
if(in_len > 244*2)
fprintf((FILE*)STDERR_FILENO, "Input size exceeds max history\n");
uint16_t umsg[244*2]; //unpunctured message
uint8_t p=0; //puncturer matrix entry
uint16_t u=0; //bits count - unpunctured message
uint16_t i=0; //bits read from the input message
while(i<in_len)
{
if(punct[p])
{
umsg[u]=in[i];
i++;
}
else
{
umsg[u]=0x7FFF;
}
u++;
p++;
p%=p_len;
}
return decode(out, umsg, u) - (u-in_len)*0x7FFF;
}
/**
* Decode one bit and update trellis.
*
* @param s0: cost of the first symbol.
* @param s1: cost of the second symbol.
* @param pos: bit position in history.
*/
void decodeBit(uint16_t s0, uint16_t s1, size_t pos)
{
static const uint16_t COST_TABLE_0[] = {0, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
static const uint16_t COST_TABLE_1[] = {0, 0xFFFF, 0xFFFF, 0, 0, 0xFFFF, 0xFFFF, 0};
for(uint8_t i = 0; i < NUM_STATES/2; i++)
{
uint32_t metric = q_AbsDiff(COST_TABLE_0[i], s0)
+ q_AbsDiff(COST_TABLE_1[i], s1);
uint32_t m0 = prevMetrics[i] + metric;
uint32_t m1 = prevMetrics[i + NUM_STATES/2] + (0x1FFFE - metric);
uint32_t m2 = prevMetrics[i] + (0x1FFFE - metric);
uint32_t m3 = prevMetrics[i + NUM_STATES/2] + metric;
uint8_t i0 = 2 * i;
uint8_t i1 = i0 + 1;
if(m0 >= m1)
{
history[pos]|=(1<<i0);
currMetrics[i0] = m1;
}
else
{
history[pos]&=~(1<<i0);
currMetrics[i0] = m0;
}
if(m2 >= m3)
{
history[pos]|=(1<<i1);
currMetrics[i1] = m3;
}
else
{
history[pos]&=~(1<<i1);
currMetrics[i1] = m2;
}
}
//swap
uint32_t tmp[NUM_STATES];
for(uint8_t i=0; i<NUM_STATES; i++)
{
tmp[i]=currMetrics[i];
}
for(uint8_t i=0; i<NUM_STATES; i++)
{
currMetrics[i]=prevMetrics[i];
prevMetrics[i]=tmp[i];
}
}
/**
* History chainback to obtain final byte array.
*
* @param out: destination byte array for decoded data.
* @param pos: starting position for the chainback.
* @param len: length of the output in bits.
* @return minimum Viterbi cost at the end of the decode sequence.
*/
uint32_t chainback(uint8_t* out, size_t pos, uint16_t len)
{
uint8_t state = 0;
size_t bitPos = len+4;
memset(out, 0, (len-1)/8+1);
while(bitPos > 0)
{
bitPos--;
pos--;
uint16_t bit = history[pos]&((1<<(state>>4)));
state >>= 1;
if(bit)
{
state |= 0x80;
out[bitPos/8]|=1<<(7-(bitPos%8));
}
}
uint32_t cost = prevMetrics[0];
for(size_t i = 0; i < NUM_STATES; i++)
{
uint32_t m = prevMetrics[i];
if(m < cost) cost = m;
}
return cost;
}
/**
* Utility function to compute the absolute value of a difference between
* two fixed-point values.
*
* @param v1: first value
* @param v2: second value
* @return abs(v1-v2)
*/
uint16_t q_AbsDiff(const uint16_t v1, const uint16_t v2)
{
if(v2 > v1) return v2 - v1;
return v1 - v2;
}
/**
* Reset the decoder state.
*
*/
void reset(void)
{
memset((uint8_t*)history, 0, 2*244);
memset((uint8_t*)currMetrics, 0, 4*NUM_STATES);
memset((uint8_t*)prevMetrics, 0, 4*NUM_STATES);
memset((uint8_t*)currMetricsData, 0, 4*NUM_STATES);
memset((uint8_t*)prevMetricsData, 0, 4*NUM_STATES);
}

Wyświetl plik

@ -0,0 +1,11 @@
#ifndef VITERBI_H
#define VITERBI_H
uint32_t decode(uint8_t* out, const uint16_t* in, uint16_t len);
uint32_t decodePunctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, uint16_t in_len, uint16_t p_len);
void decodeBit(uint16_t s0, uint16_t s1, size_t pos);
uint32_t chainback(uint8_t* out, size_t pos, uint16_t len);
uint16_t q_AbsDiff(const uint16_t v1, const uint16_t v2);
void reset(void);
#endif