update
|
@ -2,7 +2,7 @@
|
|||
The purpose of this project is to transfer data (pictures...) via a 2,7kHz SSB channel on the narrow band transponder as fast as possible.
|
||||
|
||||
# this is work in progress
|
||||
Version 0.1 is working on my linux PC and Odroid SBC.
|
||||
Version 0.2 is working on my linux PC, Odroid SBC and Raspberry 4 (3B+)
|
||||
|
||||
# Prerequisites
|
||||
* LINUX Desktop PC ... working
|
||||
|
|
391
grc/8psk_tx.grc
|
@ -1,391 +0,0 @@
|
|||
options:
|
||||
parameters:
|
||||
author: kurt
|
||||
category: '[GRC Hier Blocks]'
|
||||
cmake_opt: ''
|
||||
comment: 'requires GNU Radio 3.8xxx
|
||||
|
||||
does NOT work with 3.7x'
|
||||
copyright: ''
|
||||
description: requires GNU Radio 3.8xxx
|
||||
gen_cmake: 'Off'
|
||||
gen_linking: dynamic
|
||||
generate_options: no_gui
|
||||
hier_block_src_path: '.:'
|
||||
id: tx_8psk
|
||||
max_nouts: '0'
|
||||
output_language: python
|
||||
placement: (0,0)
|
||||
qt_qss_theme: ''
|
||||
realtime_scheduling: ''
|
||||
run: 'True'
|
||||
run_command: '{python} -u {filename}'
|
||||
run_options: run
|
||||
sizing_mode: fixed
|
||||
thread_safe_setters: ''
|
||||
title: 8PSK Modem DJ0ABR
|
||||
window_size: ''
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [8, 8]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: mixf
|
||||
id: variable
|
||||
parameters:
|
||||
comment: 'mid frequency
|
||||
|
||||
in the audio
|
||||
|
||||
spectrum. Set to get
|
||||
|
||||
lowest and highest
|
||||
|
||||
frequency within the
|
||||
|
||||
transceiver filter range.'
|
||||
value: '1500'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [336, 12.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: nfilts
|
||||
id: variable
|
||||
parameters:
|
||||
comment: ''
|
||||
value: '32'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [504, 12.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: sps
|
||||
id: variable
|
||||
parameters:
|
||||
comment: 'Samples/Symbol
|
||||
|
||||
fixed value,
|
||||
|
||||
do not change.
|
||||
|
||||
Used to adjust
|
||||
|
||||
bitrate vs. bandwidth'
|
||||
value: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [944, 36.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: analog_sig_source_x_0_0_0
|
||||
id: analog_sig_source_x
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
amp: '1'
|
||||
comment: 'the modulator output is in the baseband at 0 Hz.
|
||||
|
||||
Mix it with the required audio mid frequency.
|
||||
|
||||
cos and -sin are used to combine I and Q
|
||||
|
||||
into the final signal.'
|
||||
freq: mixf
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
offset: '0'
|
||||
phase: '0'
|
||||
samp_rate: samp_rate
|
||||
type: complex
|
||||
waveform: analog.GR_COS_WAVE
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [64, 484.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: audio_sink_0_0
|
||||
id: audio_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'send audio to
|
||||
|
||||
transceiver'
|
||||
device_name: ''
|
||||
num_inputs: '1'
|
||||
ok_to_block: 'True'
|
||||
samp_rate: samp_rate
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [840, 420.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_add_xx_0
|
||||
id: blocks_add_xx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'generate the analog
|
||||
|
||||
output signal.'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
num_inputs: '2'
|
||||
type: float
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [568, 344.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_complex_to_float_1
|
||||
id: blocks_complex_to_float
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [400, 344.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_multiply_const_vxx_0
|
||||
id: blocks_multiply_const_vxx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'reduce level for the
|
||||
|
||||
audio output, improves
|
||||
|
||||
linearity'
|
||||
const: '0.05'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
type: float
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [680, 420.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_multiply_xx_0_0
|
||||
id: blocks_multiply_xx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: "mix I und Q \nto the mid \nfrequency\nspecified in\n\"mixf\""
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
num_inputs: '2'
|
||||
type: complex
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [288, 344.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_udp_source_0
|
||||
id: blocks_udp_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: "receive an UDP data stream\nwith the bitrate of (see \ncomment samp_rate)\n\
|
||||
The stream is buffered, \nso send some bytes ahead\nto prefill the buffer\n\
|
||||
and avoid underrun"
|
||||
eof: 'False'
|
||||
ipaddr: 127.0.0.1
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
port: '40134'
|
||||
psize: '258'
|
||||
type: byte
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [736, 164.0]
|
||||
rotation: 180
|
||||
state: true
|
||||
- name: digital_constellation_modulator_0
|
||||
id: digital_constellation_modulator
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'This modulator expects "Packed Bytes"
|
||||
|
||||
which are 8 bits within one byte.
|
||||
|
||||
The UDP source block deliveres bytes,
|
||||
|
||||
so it fits perfectly.'
|
||||
constellation: digital.constellation_8psk_natural().base()
|
||||
differential: 'True'
|
||||
excess_bw: '0.25'
|
||||
log: 'False'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samples_per_symbol: resamprate
|
||||
verbose: 'False'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [272, 172.0]
|
||||
rotation: 180
|
||||
state: enabled
|
||||
- name: qtgui_freq_sink_x_0
|
||||
id: qtgui_freq_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'
|
||||
average: '0.1'
|
||||
axislabels: 'True'
|
||||
bw: samp_rate
|
||||
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'
|
||||
fc: '0'
|
||||
fftsize: '1024'
|
||||
freqhalf: 'False'
|
||||
grid: 'True'
|
||||
gui_hint: ''
|
||||
label: Relative Gain
|
||||
label1: ''
|
||||
label10: ''''''
|
||||
label2: ''''''
|
||||
label3: ''''''
|
||||
label4: ''''''
|
||||
label5: ''''''
|
||||
label6: ''''''
|
||||
label7: ''''''
|
||||
label8: ''''''
|
||||
label9: ''''''
|
||||
legend: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
name: '""'
|
||||
nconnections: '1'
|
||||
showports: 'False'
|
||||
tr_chan: '0'
|
||||
tr_level: '0.0'
|
||||
tr_mode: qtgui.TRIG_MODE_FREE
|
||||
tr_tag: '""'
|
||||
type: float
|
||||
units: dB
|
||||
update_time: '0.10'
|
||||
width1: '1'
|
||||
width10: '1'
|
||||
width2: '1'
|
||||
width3: '1'
|
||||
width4: '1'
|
||||
width5: '1'
|
||||
width6: '1'
|
||||
width7: '1'
|
||||
width8: '1'
|
||||
width9: '1'
|
||||
wintype: firdes.WIN_BLACKMAN_hARRIS
|
||||
ymax: '10'
|
||||
ymin: '-140'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [552, 552.0]
|
||||
rotation: 0
|
||||
state: disabled
|
||||
- name: resamprate
|
||||
id: parameter
|
||||
parameters:
|
||||
alias: ''
|
||||
comment: ''
|
||||
hide: none
|
||||
label: resamprate
|
||||
short_id: r
|
||||
type: intx
|
||||
value: '24'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [808, 12.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: samp_rate
|
||||
id: parameter
|
||||
parameters:
|
||||
alias: ''
|
||||
comment: Audio Rate
|
||||
hide: none
|
||||
label: samp_rate
|
||||
short_id: s
|
||||
type: intx
|
||||
value: '48000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [696, 12.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
|
||||
connections:
|
||||
- [analog_sig_source_x_0_0_0, '0', blocks_multiply_xx_0_0, '1']
|
||||
- [blocks_add_xx_0, '0', blocks_multiply_const_vxx_0, '0']
|
||||
- [blocks_add_xx_0, '0', qtgui_freq_sink_x_0, '0']
|
||||
- [blocks_complex_to_float_1, '0', blocks_add_xx_0, '0']
|
||||
- [blocks_complex_to_float_1, '1', blocks_add_xx_0, '1']
|
||||
- [blocks_multiply_const_vxx_0, '0', audio_sink_0_0, '0']
|
||||
- [blocks_multiply_xx_0_0, '0', blocks_complex_to_float_1, '0']
|
||||
- [blocks_udp_source_0, '0', digital_constellation_modulator_0, '0']
|
||||
- [digital_constellation_modulator_0, '0', blocks_multiply_xx_0_0, '0']
|
||||
|
||||
metadata:
|
||||
file_format: 1
|
|
@ -1,383 +0,0 @@
|
|||
options:
|
||||
parameters:
|
||||
author: DJ0ABR
|
||||
category: '[GRC Hier Blocks]'
|
||||
cmake_opt: ''
|
||||
comment: 'requires GNU Radio 3.8xxx
|
||||
|
||||
does NOT work with 3.7x'
|
||||
copyright: DJ0ABR
|
||||
description: requires GNU Radio 3.8xxx
|
||||
gen_cmake: 'On'
|
||||
gen_linking: dynamic
|
||||
generate_options: no_gui
|
||||
hier_block_src_path: '.:'
|
||||
id: qpsk_tx
|
||||
max_nouts: '0'
|
||||
output_language: python
|
||||
placement: (0,0)
|
||||
qt_qss_theme: ''
|
||||
realtime_scheduling: ''
|
||||
run: 'True'
|
||||
run_command: '{python} -u {filename}'
|
||||
run_options: run
|
||||
sizing_mode: fixed
|
||||
thread_safe_setters: ''
|
||||
title: 'QPSK TX-Modem '
|
||||
window_size: ''
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [8, 8]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: mixf
|
||||
id: variable
|
||||
parameters:
|
||||
comment: 'mid frequency
|
||||
|
||||
in the audio
|
||||
|
||||
spectrum. Set to get
|
||||
|
||||
lowest and highest
|
||||
|
||||
frequency within the
|
||||
|
||||
transceiver filter range.'
|
||||
value: '1500'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [360, 12.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: qpsk__constellation
|
||||
id: variable_constellation_rect
|
||||
parameters:
|
||||
comment: 'alternative:
|
||||
|
||||
[0.707+0.707j, -0.707+0.707j, -0.707-0.707j, 0.707-0.707j]
|
||||
|
||||
does not make a difference'
|
||||
const_points: '[1+1j, -1+1j, -1-1j, 1-1j]'
|
||||
imag_sect: '2'
|
||||
precision: '8'
|
||||
real_sect: '2'
|
||||
rot_sym: '4'
|
||||
soft_dec_lut: None
|
||||
sym_map: '[0, 1, 2, 3]'
|
||||
w_imag_sect: '1'
|
||||
w_real_sect: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [8, 196.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: analog_sig_source_x_0_0_0
|
||||
id: analog_sig_source_x
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
amp: '1'
|
||||
comment: 'the modulator output is in the baseband at 0 Hz.
|
||||
|
||||
Mix it with the required audio mid frequency.
|
||||
|
||||
cos and -sin are used to combine I and Q
|
||||
|
||||
into the final signal.'
|
||||
freq: mixf
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
offset: '0'
|
||||
phase: '0'
|
||||
samp_rate: samp_rate
|
||||
type: complex
|
||||
waveform: analog.GR_COS_WAVE
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [96, 476.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: audio_sink_0_0
|
||||
id: audio_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'send audio to
|
||||
|
||||
transceiver'
|
||||
device_name: ''
|
||||
num_inputs: '1'
|
||||
ok_to_block: 'True'
|
||||
samp_rate: samp_rate
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [928, 356.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_add_xx_0
|
||||
id: blocks_add_xx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'generate the analog
|
||||
|
||||
output signal: USB
|
||||
|
||||
(for LSB use substraction)'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
num_inputs: '2'
|
||||
type: float
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [696, 376.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_complex_to_float_1
|
||||
id: blocks_complex_to_float
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [512, 376.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_multiply_const_vxx_0
|
||||
id: blocks_multiply_const_vxx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'reduce level for the
|
||||
|
||||
audio output, improves
|
||||
|
||||
linearity'
|
||||
const: '0.05'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
type: float
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [784, 356.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: blocks_multiply_xx_0_0
|
||||
id: blocks_multiply_xx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: "mix I und Q \nto the mid \nfrequency\nspecified in\n\"mixf\""
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
num_inputs: '2'
|
||||
type: complex
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [400, 376.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_udp_source_0
|
||||
id: blocks_udp_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: "receive an UDP data stream\nwith the bitrate of (see \ncomment samp_rate)\n\
|
||||
The stream is buffered, \nso send some bytes ahead\nto prefill the buffer\n\
|
||||
and avoid underrun"
|
||||
eof: 'False'
|
||||
ipaddr: 127.0.0.1
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
port: '40134'
|
||||
psize: '258'
|
||||
type: byte
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [824, 148.0]
|
||||
rotation: 180
|
||||
state: enabled
|
||||
- name: digital_constellation_modulator_0
|
||||
id: digital_constellation_modulator
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: 'unpack bytes to bits
|
||||
|
||||
make symbols 2bits/sym
|
||||
|
||||
make constellation'
|
||||
constellation: qpsk__constellation
|
||||
differential: 'False'
|
||||
excess_bw: '0.35'
|
||||
log: 'False'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samples_per_symbol: resamprate
|
||||
verbose: 'False'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [392, 180.0]
|
||||
rotation: 180
|
||||
state: enabled
|
||||
- name: qtgui_freq_sink_x_0
|
||||
id: qtgui_freq_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'
|
||||
average: '0.1'
|
||||
axislabels: 'True'
|
||||
bw: samp_rate
|
||||
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'
|
||||
fc: '0'
|
||||
fftsize: '1024'
|
||||
freqhalf: 'False'
|
||||
grid: 'True'
|
||||
gui_hint: ''
|
||||
label: Relative Gain
|
||||
label1: ''
|
||||
label10: ''''''
|
||||
label2: ''''''
|
||||
label3: ''''''
|
||||
label4: ''''''
|
||||
label5: ''''''
|
||||
label6: ''''''
|
||||
label7: ''''''
|
||||
label8: ''''''
|
||||
label9: ''''''
|
||||
legend: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
name: '""'
|
||||
nconnections: '1'
|
||||
showports: 'False'
|
||||
tr_chan: '0'
|
||||
tr_level: '0.0'
|
||||
tr_mode: qtgui.TRIG_MODE_FREE
|
||||
tr_tag: '""'
|
||||
type: float
|
||||
units: dB
|
||||
update_time: '0.10'
|
||||
width1: '1'
|
||||
width10: '1'
|
||||
width2: '1'
|
||||
width3: '1'
|
||||
width4: '1'
|
||||
width5: '1'
|
||||
width6: '1'
|
||||
width7: '1'
|
||||
width8: '1'
|
||||
width9: '1'
|
||||
wintype: firdes.WIN_BLACKMAN_hARRIS
|
||||
ymax: '10'
|
||||
ymin: '-140'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [880, 576.0]
|
||||
rotation: 0
|
||||
state: disabled
|
||||
- name: resamprate
|
||||
id: parameter
|
||||
parameters:
|
||||
alias: ''
|
||||
comment: ''
|
||||
hide: none
|
||||
label: resamprate
|
||||
short_id: r
|
||||
type: intx
|
||||
value: '20'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [776, 12.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
- name: samp_rate
|
||||
id: parameter
|
||||
parameters:
|
||||
alias: ''
|
||||
comment: Audio Rate
|
||||
hide: none
|
||||
label: samp_rate
|
||||
short_id: s
|
||||
type: intx
|
||||
value: '44100'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [208, 12.0]
|
||||
rotation: 0
|
||||
state: true
|
||||
|
||||
connections:
|
||||
- [analog_sig_source_x_0_0_0, '0', blocks_multiply_xx_0_0, '1']
|
||||
- [blocks_add_xx_0, '0', blocks_multiply_const_vxx_0, '0']
|
||||
- [blocks_add_xx_0, '0', qtgui_freq_sink_x_0, '0']
|
||||
- [blocks_complex_to_float_1, '0', blocks_add_xx_0, '0']
|
||||
- [blocks_complex_to_float_1, '1', blocks_add_xx_0, '1']
|
||||
- [blocks_multiply_const_vxx_0, '0', audio_sink_0_0, '0']
|
||||
- [blocks_multiply_xx_0_0, '0', blocks_complex_to_float_1, '0']
|
||||
- [blocks_udp_source_0, '0', digital_constellation_modulator_0, '0']
|
||||
- [digital_constellation_modulator_0, '0', blocks_multiply_xx_0_0, '0']
|
||||
|
||||
metadata:
|
||||
file_format: 1
|
|
@ -1,8 +1,11 @@
|
|||
# Makefile for qo100modem
|
||||
# =======================
|
||||
|
||||
CFLAGS=-O3 -Wall
|
||||
LDLIBS= -L. -lpthread -lfftw3 -lm -lzip
|
||||
LDLIBS= -L. -lpthread -lfftw3 -lm -lzip -lfftw3_threads -lsndfile -lasound -lbass -lliquid
|
||||
CC=c++
|
||||
PROGNAME=qo100modem
|
||||
OBJ=qo100modem.o main_helper.o udp.o frame_packer.o scrambler.o crc16.o fec.o fft.o constellation.o arraysend.o
|
||||
OBJ=qo100modem.o main_helper.o udp.o frame_packer.o scrambler.o crc16.o fec.o fft.o constellation.o arraysend.o audio.o liquid_if.o
|
||||
|
||||
all: qo100modem
|
||||
|
||||
|
|
|
@ -120,7 +120,12 @@ void doArraySend()
|
|||
{
|
||||
// send first frame
|
||||
printf("Start Array Send %d\n",getSending());
|
||||
toGR_Preamble();
|
||||
|
||||
// preamble
|
||||
int numframespreamble = 3* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1;
|
||||
for(int i=0; i<numframespreamble; i++)
|
||||
toGR_sendData(TXarray, txtype, filestat);
|
||||
|
||||
if(txlen <= PAYLOADLEN)
|
||||
{
|
||||
// we just need to send one frame
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
||||
* =========================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* audio.c ... functions to handle audio in/out via a soundcard
|
||||
* uses the "BASS" library
|
||||
*
|
||||
* captures samples from the sound card.
|
||||
* Samples are 32-bit floats in a range of -1 to +1
|
||||
* get these samples from the thread safe fifo: cap_read_fifo(&floatvariable)
|
||||
*
|
||||
* plays samples to the sound card
|
||||
* Samples are 32-bit floats in a range of -1 to +1
|
||||
* play the samples by calling the thread save function: pb_write_fifo(floatsample)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qo100modem.h"
|
||||
|
||||
//BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user);
|
||||
DWORD CALLBACK WriteStream(HSTREAM handle, float *buffer, DWORD length, void *user);
|
||||
int pb_read_fifo(float *data, int elements);
|
||||
void close_audio();
|
||||
|
||||
#define CHANNELS 1 // no of channels used
|
||||
|
||||
HRECORD rchan = 0; // recording channel
|
||||
BASS_INFO info;
|
||||
HSTREAM stream = 0;
|
||||
|
||||
int init_audio()
|
||||
{
|
||||
close_audio();
|
||||
printf("init audio, caprate:%d\n",caprate);
|
||||
|
||||
// check the correct BASS was loaded
|
||||
if (HIWORD(BASS_GetVersion()) != BASSVERSION)
|
||||
{
|
||||
printf("An incorrect version of BASS was loaded\n");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
// initalize default recording device
|
||||
if (!BASS_RecordInit(-1))
|
||||
{
|
||||
printf("Can't initialize recording device\n");
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
// initialize default output device
|
||||
if (!BASS_Init(-1, caprate, 0, NULL, NULL))
|
||||
{
|
||||
printf("Can't initialize output device\n");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
// set capture callback
|
||||
rchan = BASS_RecordStart(caprate, CHANNELS, BASS_SAMPLE_FLOAT, RecordingCallback, 0);
|
||||
if (!rchan) {
|
||||
printf("Can't start capturing\n");
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
// set play callback
|
||||
BASS_GetInfo(&info);
|
||||
stream = BASS_StreamCreate(info.freq, CHANNELS, BASS_SAMPLE_FLOAT, (STREAMPROC*)WriteStream, 0); // sample: 32 bit float
|
||||
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, 0); // no buffering for minimum latency
|
||||
BASS_ChannelPlay(stream, FALSE); // start it
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close_audio()
|
||||
{
|
||||
if(stream != 0)
|
||||
{
|
||||
//BASS_RecordFree();
|
||||
int r = BASS_Free();
|
||||
if(!r)
|
||||
printf("Bass_free error: %d\n", BASS_ErrorGetCode());
|
||||
stream = 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// capture callback
|
||||
// length: bytes. short=2byte, 2channels, so it requests samples*4
|
||||
BOOL CALLBACK RecordingCallback(HRECORD handle, const void *buffer, DWORD length, void *user)
|
||||
{
|
||||
//printf("captured %ld samples\n",length/sizeof(float));
|
||||
|
||||
float *fbuffer = (float *)buffer;
|
||||
//printf("w:%ld ",length/sizeof(float));
|
||||
for(int i=0; i<(length/sizeof(float)); i+=CHANNELS)
|
||||
{
|
||||
//printf("%f\n",fbuffer[i]);
|
||||
cap_write_fifo(fbuffer[i]);
|
||||
}
|
||||
|
||||
return TRUE; // continue recording
|
||||
}
|
||||
*/
|
||||
// play callback
|
||||
// length: bytes. float=4byte, 2channels, so it requests samples*8
|
||||
DWORD CALLBACK WriteStream(HSTREAM handle, float *buffer, DWORD length, void *user)
|
||||
{
|
||||
int ret = pb_read_fifo(buffer,length/sizeof(float));
|
||||
if(ret == 0)
|
||||
{
|
||||
// fifo empty, send 00
|
||||
memset(buffer,0,length);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
// ================ thread safe fifo for audio callback routines ===============
|
||||
|
||||
pthread_mutex_t cap_crit_sec;
|
||||
pthread_mutex_t pb_crit_sec;
|
||||
#define CAP_LOCK pthread_mutex_lock(&cap_crit_sec)
|
||||
#define CAP_UNLOCK pthread_mutex_unlock(&cap_crit_sec)
|
||||
#define PB_LOCK pthread_mutex_lock(&pb_crit_sec)
|
||||
#define PB_UNLOCK pthread_mutex_unlock(&pb_crit_sec)
|
||||
|
||||
#define AUDIO_BUFFERMAXTIME 2 // fifo can buffer this time in [s]
|
||||
#define AUDIO_PLAYBACK_BUFLEN (48000 * 10) // space for 10 seconds of samples
|
||||
/*#define AUDIO_CAPTURE_BUFLEN (48000*CHANNELS*AUDIO_BUFFERMAXTIME*UPSAMPLING)
|
||||
|
||||
int cap_wridx=0;
|
||||
int cap_rdidx=0;
|
||||
float cap_buffer[AUDIO_CAPTURE_BUFLEN];
|
||||
*/
|
||||
int pb_wridx=0;
|
||||
int pb_rdidx=0;
|
||||
float pb_buffer[AUDIO_PLAYBACK_BUFLEN];
|
||||
|
||||
/*
|
||||
// write one sample into the fifo
|
||||
// overwrite old data if the fifo is full
|
||||
void cap_write_fifo(float sample)
|
||||
{
|
||||
CAP_LOCK;
|
||||
cap_buffer[cap_wridx] = sample;
|
||||
if(++cap_wridx >= AUDIO_CAPTURE_BUFLEN) cap_wridx = 0;
|
||||
CAP_UNLOCK;
|
||||
}
|
||||
|
||||
int cap_read_fifo(float *data)
|
||||
{
|
||||
CAP_LOCK;
|
||||
|
||||
if (cap_rdidx == cap_wridx)
|
||||
{
|
||||
// Fifo empty, no data available
|
||||
CAP_UNLOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*data = cap_buffer[cap_rdidx];
|
||||
if(++cap_rdidx >= AUDIO_CAPTURE_BUFLEN) cap_rdidx = 0;
|
||||
CAP_UNLOCK;
|
||||
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
void pb_write_fifo(float sample)
|
||||
{
|
||||
PB_LOCK;
|
||||
|
||||
// check if there is free space in fifo
|
||||
if(pb_fifo_freespace(1) == 0)
|
||||
{
|
||||
PB_UNLOCK;
|
||||
printf("************* pb fifo full\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pb_buffer[pb_wridx] = sample;
|
||||
if(++pb_wridx >= AUDIO_PLAYBACK_BUFLEN) pb_wridx = 0;
|
||||
PB_UNLOCK;
|
||||
//printf("write: pbw:%d pbr:%d\n",pb_wridx,pb_rdidx);
|
||||
}
|
||||
|
||||
int pb_fifo_freespace(int nolock)
|
||||
{
|
||||
int freebuf = 0;
|
||||
|
||||
if(nolock == 0) PB_LOCK;
|
||||
|
||||
/*freebuf = AUDIO_PLAYBACK_BUFLEN - ((pb_wridx+AUDIO_PLAYBACK_BUFLEN+1 - pb_rdidx)%AUDIO_PLAYBACK_BUFLEN);
|
||||
freebuf %= AUDIO_PLAYBACK_BUFLEN;*/
|
||||
|
||||
int elemInFifo = (pb_wridx + AUDIO_PLAYBACK_BUFLEN - pb_rdidx) % AUDIO_PLAYBACK_BUFLEN;
|
||||
freebuf = AUDIO_PLAYBACK_BUFLEN - elemInFifo;
|
||||
|
||||
if(nolock == 0) PB_UNLOCK;
|
||||
|
||||
//printf("fifolen:%d check: pbw:%d pbr:%d freebuf:%d\n",AUDIO_PLAYBACK_BUFLEN,pb_wridx,pb_rdidx,freebuf);
|
||||
|
||||
return freebuf;
|
||||
}
|
||||
|
||||
// read elements floats from fifo or return 0 if not enough floats are available
|
||||
int pb_read_fifo(float *data, int elements)
|
||||
{
|
||||
//printf("pb read fifo: %d\n",elements);
|
||||
PB_LOCK;
|
||||
|
||||
int e = AUDIO_PLAYBACK_BUFLEN - pb_fifo_freespace(1);
|
||||
//if (pb_rdidx == pb_wridx)
|
||||
if(e < elements)
|
||||
{
|
||||
// Fifo empty, no data available
|
||||
PB_UNLOCK;
|
||||
//printf("pb fifo empty, need:%d have:%d size:%d\n",elements,e,AUDIO_PLAYBACK_BUFLEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(int i=0; i<elements; i++)
|
||||
{
|
||||
data[i] = pb_buffer[pb_rdidx];
|
||||
if(++pb_rdidx >= AUDIO_PLAYBACK_BUFLEN) pb_rdidx = 0;
|
||||
}
|
||||
//printf("read %d floats\n",elements);
|
||||
|
||||
PB_UNLOCK;
|
||||
return 1;
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
||||
* =========================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qo100modem.h"
|
||||
#include "liquid.h"
|
||||
|
||||
fec fecobjTX;
|
||||
fec fecobjRX;
|
||||
fec_scheme fs = LIQUID_FEC_SECDED3932; // error-correcting scheme
|
||||
uint8_t encoded_message[UdpBlocklen];
|
||||
uint8_t decoded_message[PayloadLen+framenumlen+CRClen];
|
||||
|
||||
uint8_t *cfec_Reconstruct(uint8_t *darr)
|
||||
{
|
||||
memset(decoded_message,0,(PayloadLen+framenumlen+CRClen));
|
||||
fec_decode(fecobjRX, (PayloadLen+framenumlen+CRClen), darr, decoded_message);
|
||||
|
||||
return decoded_message;
|
||||
}
|
||||
|
||||
uint8_t *GetFEC(uint8_t *txblock, int len)
|
||||
{
|
||||
if(len != (PayloadLen+framenumlen+CRClen))
|
||||
{
|
||||
printf("wrong FEC encode length, len:%d Payloadlen:%d\n",len,PayloadLen);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fec_encode(fecobjTX, len, txblock, encoded_message);
|
||||
|
||||
return encoded_message;
|
||||
}
|
||||
|
||||
void initFEC()
|
||||
{
|
||||
int n_enc = fec_get_enc_msg_length(fs,(PayloadLen+framenumlen+CRClen));
|
||||
if(n_enc != UdpBlocklen)
|
||||
{
|
||||
printf("wrong FEC init length\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
fecobjTX = fec_create(fs,NULL);
|
||||
fecobjRX = fec_create(fs,NULL);
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ uint8_t *Pack(uint8_t *payload, int type, int status, int *plen)
|
|||
}
|
||||
}*/
|
||||
|
||||
#define MAXHEADERRS 0
|
||||
#define MAXHEADERRS 3
|
||||
|
||||
/*
|
||||
* Header erros will not cause any data errors because the CRC will filter out
|
||||
|
@ -298,7 +298,7 @@ uint8_t *getPayload(uint8_t *rxb)
|
|||
int framenumrx = (frame.status & 0xc0)>>6; // frame counter MSB
|
||||
framenumrx <<= 8;
|
||||
framenumrx += frame.counter_LSB; // frame counter LSB
|
||||
//printf("Frame no.: %d\n",framenumrx);
|
||||
|
||||
if (lastframenum != framenumrx) rx_status |= 4;
|
||||
lastframenum = framenumrx;
|
||||
if (++lastframenum >= 1024) lastframenum = 0; // 1024 = 2^10 (10 bit frame number)
|
||||
|
@ -317,6 +317,8 @@ uint8_t *getPayload(uint8_t *rxb)
|
|||
payload[8] = 0;
|
||||
payload[9] = 0;
|
||||
|
||||
//printf("Frame no.: %d, type:%d, minfo:%d\n",framenumrx,payload[0],payload[3]);
|
||||
|
||||
memcpy(payload+10,frame.payload,PAYLOADLEN);
|
||||
|
||||
return payload;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
sudo apt install git autoconf libsndfile-dev libasound-dev
|
||||
git clone git://github.com/jgaeddert/liquid-dsp.git
|
||||
cd liquid-dsp
|
||||
./bootstrap.sh
|
||||
./configure
|
||||
make -j 8
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
||||
* =========================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* liquid_dsp_interface.c ... functions using liquid-dsp
|
||||
*
|
||||
* liquid-dsp must be previously installed by running ./liquid-dsp-install (under linux)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qo100modem.h"
|
||||
|
||||
void modulator(uint8_t sym_in);
|
||||
void close_dsp();
|
||||
|
||||
// modem objects
|
||||
modulation_scheme ms = LIQUID_MODEM_QPSK;
|
||||
modem mod = NULL;
|
||||
|
||||
// NCOs for mixing baseband <-> 1500 Hz
|
||||
#define FREQUENCY 1500
|
||||
int type = LIQUID_NCO; // nco type
|
||||
nco_crcf upnco = NULL;
|
||||
|
||||
// TX-Interpolator Filter Parameters
|
||||
// 44100 input rate for 2205 Sym/s = 20
|
||||
// change for other rates
|
||||
firinterp_crcf TX_interpolator = NULL;
|
||||
unsigned int k_SampPerSymb = 20; // 44100 / (4410/2)
|
||||
unsigned int m_filterDelay_Symbols = 15; // not too short for good filter
|
||||
float beta_excessBW = 0.3f; // filter excess bandwidth factor
|
||||
float tau_FracSymbOffset = -0.2f; // fractional symbol offset
|
||||
|
||||
int init_dsp()
|
||||
{
|
||||
close_dsp();
|
||||
printf("create DSP\n");
|
||||
|
||||
k_SampPerSymb = txinterpolfactor;
|
||||
if(bitsPerSymbol == 2)
|
||||
ms = LIQUID_MODEM_QPSK;
|
||||
else
|
||||
ms = LIQUID_MODEM_DPSK8;
|
||||
|
||||
// create modulator
|
||||
mod = modem_create(ms);
|
||||
|
||||
// create NCO for upmixing to 1500 Hz
|
||||
double RADIANS_PER_SAMPLE = ((2.0*M_PI*(double)FREQUENCY)/(float)caprate);
|
||||
|
||||
upnco = nco_crcf_create(LIQUID_NCO);
|
||||
nco_crcf_set_phase(upnco, 0.0f);
|
||||
nco_crcf_set_frequency(upnco, RADIANS_PER_SAMPLE);
|
||||
|
||||
// TX: Interpolator Filter
|
||||
// compute delay
|
||||
while (tau_FracSymbOffset < 0) tau_FracSymbOffset += 1.0f; // ensure positive tau
|
||||
float g = k_SampPerSymb*tau_FracSymbOffset; // number of samples offset
|
||||
int ds=floorf(g); // additional symbol delay
|
||||
float dt = (g - (float)ds); // fractional sample offset
|
||||
// force dt to be in [0.5,0.5]
|
||||
if (dt > 0.5f)
|
||||
{
|
||||
dt -= 1.0f;
|
||||
ds++;
|
||||
}
|
||||
|
||||
// calculate filter coeffs
|
||||
unsigned int h_len_NumFilterCoeefs = 2 * k_SampPerSymb * m_filterDelay_Symbols + 1;
|
||||
float h[h_len_NumFilterCoeefs];
|
||||
liquid_firdes_prototype( LIQUID_FIRFILT_RRC,
|
||||
k_SampPerSymb,
|
||||
m_filterDelay_Symbols,
|
||||
beta_excessBW,
|
||||
dt,
|
||||
h);
|
||||
// create the filter
|
||||
TX_interpolator = firinterp_crcf_create(k_SampPerSymb,h,h_len_NumFilterCoeefs);
|
||||
|
||||
printf("DSP created\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void close_dsp()
|
||||
{
|
||||
if(mod != NULL) modem_destroy(mod);
|
||||
if(upnco != NULL) nco_crcf_destroy(upnco);
|
||||
if(TX_interpolator != NULL) firinterp_crcf_destroy(TX_interpolator);
|
||||
mod = NULL;
|
||||
upnco = NULL;
|
||||
TX_interpolator = NULL;
|
||||
}
|
||||
|
||||
// d ... symbols to send
|
||||
// len ... number of symbols in d
|
||||
void sendToModulator(uint8_t *d, int len)
|
||||
{
|
||||
|
||||
//printf("sendToModulator %d bytes\n",len);
|
||||
|
||||
int symanz = len * 8 / bitsPerSymbol;
|
||||
uint8_t syms[symanz];
|
||||
if(bitsPerSymbol == 2)
|
||||
convertBytesToSyms_QPSK(d, syms, len);
|
||||
else
|
||||
convertBytesToSyms_8PSK(d, syms, len);
|
||||
|
||||
for(int i=0; i<symanz; i++)
|
||||
{
|
||||
// remove gray code
|
||||
// this adds gray code, liquid adds it again which removes it
|
||||
syms[i] ^= (syms[i]>>1);
|
||||
|
||||
modulator(syms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// call for every symbol
|
||||
// modulates, filters and upmixes symbols and send it to soundcard
|
||||
void modulator(uint8_t sym_in)
|
||||
{
|
||||
liquid_float_complex sample;
|
||||
modem_modulate(mod, sym_in, &sample);
|
||||
|
||||
//printf("TX ================= sample: %f + i%f\n", sample.real, sample.imag);
|
||||
|
||||
// interpolate by k_SampPerSymb
|
||||
liquid_float_complex y[k_SampPerSymb];
|
||||
firinterp_crcf_execute(TX_interpolator, sample, y);
|
||||
|
||||
for(unsigned int i=0; i<k_SampPerSymb; i++)
|
||||
{
|
||||
// move sample to 1,5kHz carrier
|
||||
nco_crcf_step(upnco);
|
||||
float minus_sine = -nco_crcf_sin(upnco);
|
||||
float cosinus = nco_crcf_cos(upnco);
|
||||
float re = y[i].real * cosinus;
|
||||
float im = y[i].imag * minus_sine;
|
||||
float usb = re + im;
|
||||
// value is -1 .. +1
|
||||
|
||||
// adapt speed to soundcard samplerate
|
||||
int fs;
|
||||
while(1)
|
||||
{
|
||||
fs = pb_fifo_freespace(0);
|
||||
if(fs) break;
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
pb_write_fifo(usb * 0.2); // reduce volume and send to soundcard
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ int isRunning(char *prgname)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// signal handler
|
||||
void sighandler(int signum)
|
||||
{
|
||||
|
|
|
@ -59,7 +59,6 @@ int speedmode = 4;
|
|||
int bitsPerSymbol = 2; // QPSK=2, 8PSK=3
|
||||
int constellationSize = 4; // QPSK=4, 8PSK=8
|
||||
|
||||
|
||||
char localIP[]={"127.0.0.1"};
|
||||
char ownfilename[]={"qo100modem"};
|
||||
char myIP[20];
|
||||
|
@ -68,6 +67,9 @@ int fixappIP = 0;
|
|||
int restart_modems = 0;
|
||||
int doNotLoadModems = 0;
|
||||
|
||||
int caprate = 44100;
|
||||
int txinterpolfactor = 20;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt = 0;
|
||||
|
@ -99,7 +101,7 @@ char *modemip = NULL;
|
|||
}
|
||||
}
|
||||
|
||||
if(isRunning(ownfilename) == 1)
|
||||
if(doNotLoadModems == 0 && isRunning(ownfilename) == 1)
|
||||
exit(0);
|
||||
|
||||
install_signal_handler();
|
||||
|
@ -107,10 +109,11 @@ char *modemip = NULL;
|
|||
init_packer();
|
||||
initFEC();
|
||||
init_fft();
|
||||
init_audio();
|
||||
|
||||
// start udp RX to listen for broadcast search message from Application
|
||||
UdpRxInit(&BC_sock_AppToModem, UdpBCport_AppToModem, &bc_rxdata, &keeprunning);
|
||||
|
||||
|
||||
// start udp RX for data from application
|
||||
UdpRxInit(&DATA_sock_AppToModem, UdpDataPort_AppToModem, &appdata_rxdata, &keeprunning);
|
||||
|
||||
|
@ -169,7 +172,6 @@ SPEEDRATE sr[9] = {
|
|||
|
||||
void startModem()
|
||||
{
|
||||
char stx[512];
|
||||
char srx[512];
|
||||
|
||||
if(speedmode >= 0 && speedmode <=5)
|
||||
|
@ -183,30 +185,24 @@ char srx[512];
|
|||
constellationSize = (1<<bitsPerSymbol); // QPSK=4, 8PSK=8
|
||||
}
|
||||
|
||||
caprate = sr[speedmode].audio;
|
||||
txinterpolfactor = sr[speedmode].tx;
|
||||
|
||||
if(doNotLoadModems == 1) return;
|
||||
|
||||
if(speedmode >= 0 && speedmode <=5)
|
||||
{
|
||||
sprintf(stx,"python3 qpsk_tx.py -r %d -s %d &",sr[speedmode].tx,sr[speedmode].audio);
|
||||
sprintf(srx,"python3 qpsk_rx.py -r %d -s %d &",sr[speedmode].rx,sr[speedmode].audio);
|
||||
}
|
||||
else if(speedmode >= 6 && speedmode <=7)
|
||||
{
|
||||
sprintf(stx,"python3 tx_8psk.py -r %d -s %d &",sr[speedmode].tx,sr[speedmode].audio);
|
||||
sprintf(srx,"python3 rx_8psk.py -r %d -s %d &",sr[speedmode].rx,sr[speedmode].audio);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("wrong modem number\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// the TX modem needs the local IP address as a parameter -i ip
|
||||
if(run_console_program(stx) == -1)
|
||||
{
|
||||
printf("cannot start TX modem\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// int TX audio and modulator
|
||||
init_dsp();
|
||||
init_audio();
|
||||
|
||||
// the RX modem needs the app's IP address as a parameter -i ip
|
||||
if(run_console_program(srx) == -1)
|
||||
|
@ -354,13 +350,22 @@ void appdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
|
|||
int r = system("sudo shutdown now");
|
||||
exit(r);
|
||||
}
|
||||
|
||||
|
||||
if(getSending() == 1) return; // already sending (Array sending)
|
||||
|
||||
if(minfo == 0)
|
||||
{
|
||||
toGR_Preamble(); // first transmission of a data block, send preamble
|
||||
toGR_sendData(pdata+2, type, minfo);
|
||||
// this is the first frame of a larger file
|
||||
// send it multiple times, like a preamble, to give the
|
||||
// receiver some time for synchronisation
|
||||
// duration: 3 seconds
|
||||
// caprate: samples/s. This are symbols: caprate/txinterpolfactor
|
||||
// and bits: symbols * bitsPerSymbol
|
||||
// and bytes/second: bits/8 = (caprate/txinterpolfactor) * bitsPerSymbol / 8
|
||||
// one frame has 258 bytes, so we need for 5s: 5* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
|
||||
int numframespreamble = 3* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1;
|
||||
for(int i=0; i<numframespreamble; i++)
|
||||
toGR_sendData(pdata+2, type, minfo);
|
||||
}
|
||||
else if((len-2) < PAYLOADLEN)
|
||||
{
|
||||
|
@ -376,37 +381,15 @@ void appdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
|
|||
}
|
||||
}
|
||||
|
||||
void toGR_Preamble()
|
||||
{
|
||||
srand(123);
|
||||
// send random data, rx can sync
|
||||
uint8_t data[UDPBLOCKLEN];
|
||||
|
||||
// 1byte 1,8ms (about 2ms)
|
||||
int timeforframe = 2 * UDPBLOCKLEN; // 160 ms
|
||||
int repeats = 8000 /timeforframe; // for 8000ms = 8s
|
||||
|
||||
for(int i=0; i<repeats; i++)
|
||||
{
|
||||
for(int j=0; j<UDPBLOCKLEN; j++)
|
||||
data[j] = rand();
|
||||
|
||||
sendUDP(localIP,UdpDataPort_toGR,data,UDPBLOCKLEN);
|
||||
usleep(300000);
|
||||
}
|
||||
}
|
||||
|
||||
void toGR_sendData(uint8_t *data, int type, int status)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t *txdata = Pack(data,type,status,&len);
|
||||
|
||||
//printf("senddata %d\n",len);
|
||||
//showbytestring((char *)"BERtx: ", txdata, len);
|
||||
|
||||
if(txdata != NULL)
|
||||
{
|
||||
sendUDP(localIP,UdpDataPort_toGR,txdata,len);
|
||||
}
|
||||
sendToModulator(txdata,len);
|
||||
}
|
||||
|
||||
#define SPEEDMEAN 3
|
||||
|
@ -469,7 +452,7 @@ void measure_speed(int len)
|
|||
meansumbytes = 0;
|
||||
}
|
||||
|
||||
// called by UDP RX thread for data from GR
|
||||
// called by UDP RX thread for data from GnuRadio Receiver
|
||||
void GRdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
|
||||
{
|
||||
// raw symbols
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "frameformat.h"
|
||||
#include "main_helper.h"
|
||||
#include "udp.h"
|
||||
#include "bass.h"
|
||||
#include <liquid/liquid.h>
|
||||
|
||||
#define jpg_tempfilename "rxdata.jpg"
|
||||
|
||||
|
@ -45,7 +47,6 @@ int cfec_Reconstruct(uint8_t *darr, uint8_t *destination);
|
|||
uint8_t *Pack(uint8_t *payload, int type, int status, int *plen);
|
||||
void GetFEC(uint8_t *txblock, int len, uint8_t *destArray);
|
||||
void initFEC();
|
||||
void toGR_Preamble();
|
||||
void toGR_sendData(uint8_t *data, int type, int status);
|
||||
uint16_t *make_waterfall(uint8_t *pdata, int len, int *retlen);
|
||||
void init_fft();
|
||||
|
@ -62,12 +63,17 @@ void convertBytesToSyms_8PSK(uint8_t *bytes, uint8_t *syms, int bytenum);
|
|||
void rotate8PSKsyms(uint8_t *src, uint8_t *dst, int len);
|
||||
uint8_t * rotateBack8PSK(uint8_t *buf, int len, int rotations);
|
||||
void setSending(uint8_t onoff);
|
||||
void toGR_Preamble();
|
||||
int getSending();
|
||||
void doArraySend();
|
||||
int arraySend(uint8_t *data, int length, uint8_t type, char *filename);
|
||||
void shiftleft(uint8_t *data, int shiftnum, int len);
|
||||
void showbytestring16(char *title, uint16_t *data, int anz);
|
||||
int isTXRunning(char *prgname);
|
||||
int pb_fifo_freespace(int nolock);
|
||||
int init_audio();
|
||||
void sendToModulator(uint8_t *d, int len);
|
||||
void pb_write_fifo(float sample);
|
||||
int init_dsp();
|
||||
|
||||
|
||||
extern int keeprunning;
|
||||
|
@ -76,7 +82,8 @@ extern int speed;
|
|||
extern int speedmode;
|
||||
extern int bitsPerSymbol;
|
||||
extern int constellationSize;
|
||||
|
||||
extern int caprate;
|
||||
extern int txinterpolfactor;
|
||||
|
||||
/*
|
||||
* Constellation as produced by the GR Constellation Decoder:
|
||||
|
|
|
@ -42,8 +42,8 @@ class qpsk_rx(gr.top_block):
|
|||
self.qpsk__constellation = qpsk__constellation = digital.constellation_rect([0.707+0.707j, -0.707+0.707j, -0.707-0.707j, 0.707-0.707j], [0, 1, 2, 3],
|
||||
4, 2, 2, 1, 1).base()
|
||||
self.qpsk__constellation.gen_soft_dec_lut(8)
|
||||
self.outputsps = outputsps = 7
|
||||
self.nfilts = nfilts = 32
|
||||
self.outputsps = outputsps = 8
|
||||
self.nfilts = nfilts = 15
|
||||
self.mixf = mixf = 1500
|
||||
|
||||
##################################################
|
||||
|
|
140
modem/qpsk_tx.py
|
@ -1,140 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0
|
||||
#
|
||||
# GNU Radio Python Flow Graph
|
||||
# Title: QPSK TX-Modem
|
||||
# Author: DJ0ABR
|
||||
# Copyright: DJ0ABR
|
||||
# Description: requires GNU Radio 3.8xxx
|
||||
# GNU Radio version: 3.8.2.0
|
||||
|
||||
from gnuradio import analog
|
||||
from gnuradio import audio
|
||||
from gnuradio import blocks
|
||||
from gnuradio import digital
|
||||
from gnuradio import gr
|
||||
from gnuradio.filter import firdes
|
||||
import sys
|
||||
import signal
|
||||
from argparse import ArgumentParser
|
||||
from gnuradio.eng_arg import eng_float, intx
|
||||
from gnuradio import eng_notation
|
||||
|
||||
|
||||
class qpsk_tx(gr.top_block):
|
||||
|
||||
def __init__(self, resamprate=20, samp_rate=44100):
|
||||
gr.top_block.__init__(self, "QPSK TX-Modem ")
|
||||
|
||||
##################################################
|
||||
# Parameters
|
||||
##################################################
|
||||
self.resamprate = resamprate
|
||||
self.samp_rate = samp_rate
|
||||
|
||||
##################################################
|
||||
# Variables
|
||||
##################################################
|
||||
self.qpsk__constellation = qpsk__constellation = digital.constellation_rect([1+1j, -1+1j, -1-1j, 1-1j], [0, 1, 2, 3],
|
||||
4, 2, 2, 1, 1).base()
|
||||
self.mixf = mixf = 1500
|
||||
|
||||
##################################################
|
||||
# Blocks
|
||||
##################################################
|
||||
self.digital_constellation_modulator_0 = digital.generic_mod(
|
||||
constellation=qpsk__constellation,
|
||||
differential=False,
|
||||
samples_per_symbol=resamprate,
|
||||
pre_diff_code=True,
|
||||
excess_bw=0.35,
|
||||
verbose=False,
|
||||
log=False)
|
||||
self.blocks_udp_source_0 = blocks.udp_source(gr.sizeof_char*1, '127.0.0.1', 40134, 258, False)
|
||||
self.blocks_multiply_xx_0_0 = blocks.multiply_vcc(1)
|
||||
self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(0.05)
|
||||
self.blocks_complex_to_float_1 = blocks.complex_to_float(1)
|
||||
self.blocks_add_xx_0 = blocks.add_vff(1)
|
||||
self.audio_sink_0_0 = audio.sink(samp_rate, '', True)
|
||||
self.analog_sig_source_x_0_0_0 = analog.sig_source_c(samp_rate, analog.GR_COS_WAVE, mixf, 1, 0, 0)
|
||||
|
||||
|
||||
|
||||
##################################################
|
||||
# Connections
|
||||
##################################################
|
||||
self.connect((self.analog_sig_source_x_0_0_0, 0), (self.blocks_multiply_xx_0_0, 1))
|
||||
self.connect((self.blocks_add_xx_0, 0), (self.blocks_multiply_const_vxx_0, 0))
|
||||
self.connect((self.blocks_complex_to_float_1, 0), (self.blocks_add_xx_0, 0))
|
||||
self.connect((self.blocks_complex_to_float_1, 1), (self.blocks_add_xx_0, 1))
|
||||
self.connect((self.blocks_multiply_const_vxx_0, 0), (self.audio_sink_0_0, 0))
|
||||
self.connect((self.blocks_multiply_xx_0_0, 0), (self.blocks_complex_to_float_1, 0))
|
||||
self.connect((self.blocks_udp_source_0, 0), (self.digital_constellation_modulator_0, 0))
|
||||
self.connect((self.digital_constellation_modulator_0, 0), (self.blocks_multiply_xx_0_0, 0))
|
||||
|
||||
|
||||
def get_resamprate(self):
|
||||
return self.resamprate
|
||||
|
||||
def set_resamprate(self, resamprate):
|
||||
self.resamprate = resamprate
|
||||
|
||||
def get_samp_rate(self):
|
||||
return self.samp_rate
|
||||
|
||||
def set_samp_rate(self, samp_rate):
|
||||
self.samp_rate = samp_rate
|
||||
self.analog_sig_source_x_0_0_0.set_sampling_freq(self.samp_rate)
|
||||
|
||||
def get_qpsk__constellation(self):
|
||||
return self.qpsk__constellation
|
||||
|
||||
def set_qpsk__constellation(self, qpsk__constellation):
|
||||
self.qpsk__constellation = qpsk__constellation
|
||||
|
||||
def get_mixf(self):
|
||||
return self.mixf
|
||||
|
||||
def set_mixf(self, mixf):
|
||||
self.mixf = mixf
|
||||
self.analog_sig_source_x_0_0_0.set_frequency(self.mixf)
|
||||
|
||||
|
||||
|
||||
|
||||
def argument_parser():
|
||||
description = 'requires GNU Radio 3.8xxx'
|
||||
parser = ArgumentParser(description=description)
|
||||
parser.add_argument(
|
||||
"-r", "--resamprate", dest="resamprate", type=intx, default=20,
|
||||
help="Set resamprate [default=%(default)r]")
|
||||
parser.add_argument(
|
||||
"-s", "--samp-rate", dest="samp_rate", type=intx, default=44100,
|
||||
help="Set samp_rate [default=%(default)r]")
|
||||
return parser
|
||||
|
||||
|
||||
def main(top_block_cls=qpsk_tx, options=None):
|
||||
if options is None:
|
||||
options = argument_parser().parse_args()
|
||||
tb = top_block_cls(resamprate=options.resamprate, samp_rate=options.samp_rate)
|
||||
|
||||
def sig_handler(sig=None, frame=None):
|
||||
tb.stop()
|
||||
tb.wait()
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
|
||||
tb.start()
|
||||
|
||||
tb.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
145
modem/tx_8psk.py
|
@ -1,145 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0
|
||||
#
|
||||
# GNU Radio Python Flow Graph
|
||||
# Title: 8PSK Modem DJ0ABR
|
||||
# Author: kurt
|
||||
# Description: requires GNU Radio 3.8xxx
|
||||
# GNU Radio version: 3.8.2.0
|
||||
|
||||
from gnuradio import analog
|
||||
from gnuradio import audio
|
||||
from gnuradio import blocks
|
||||
from gnuradio import digital
|
||||
from gnuradio import gr
|
||||
from gnuradio.filter import firdes
|
||||
import sys
|
||||
import signal
|
||||
from argparse import ArgumentParser
|
||||
from gnuradio.eng_arg import eng_float, intx
|
||||
from gnuradio import eng_notation
|
||||
|
||||
|
||||
class tx_8psk(gr.top_block):
|
||||
|
||||
def __init__(self, resamprate=24, samp_rate=48000):
|
||||
gr.top_block.__init__(self, "8PSK Modem DJ0ABR")
|
||||
|
||||
##################################################
|
||||
# Parameters
|
||||
##################################################
|
||||
self.resamprate = resamprate
|
||||
self.samp_rate = samp_rate
|
||||
|
||||
##################################################
|
||||
# Variables
|
||||
##################################################
|
||||
self.sps = sps = 1
|
||||
self.nfilts = nfilts = 32
|
||||
self.mixf = mixf = 1500
|
||||
|
||||
##################################################
|
||||
# Blocks
|
||||
##################################################
|
||||
self.digital_constellation_modulator_0 = digital.generic_mod(
|
||||
constellation=digital.constellation_8psk_natural().base(),
|
||||
differential=True,
|
||||
samples_per_symbol=resamprate,
|
||||
pre_diff_code=True,
|
||||
excess_bw=0.25,
|
||||
verbose=False,
|
||||
log=False)
|
||||
self.blocks_udp_source_0 = blocks.udp_source(gr.sizeof_char*1, '127.0.0.1', 40134, 258, False)
|
||||
self.blocks_multiply_xx_0_0 = blocks.multiply_vcc(1)
|
||||
self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(0.05)
|
||||
self.blocks_complex_to_float_1 = blocks.complex_to_float(1)
|
||||
self.blocks_add_xx_0 = blocks.add_vff(1)
|
||||
self.audio_sink_0_0 = audio.sink(samp_rate, '', True)
|
||||
self.analog_sig_source_x_0_0_0 = analog.sig_source_c(samp_rate, analog.GR_COS_WAVE, mixf, 1, 0, 0)
|
||||
|
||||
|
||||
|
||||
##################################################
|
||||
# Connections
|
||||
##################################################
|
||||
self.connect((self.analog_sig_source_x_0_0_0, 0), (self.blocks_multiply_xx_0_0, 1))
|
||||
self.connect((self.blocks_add_xx_0, 0), (self.blocks_multiply_const_vxx_0, 0))
|
||||
self.connect((self.blocks_complex_to_float_1, 0), (self.blocks_add_xx_0, 0))
|
||||
self.connect((self.blocks_complex_to_float_1, 1), (self.blocks_add_xx_0, 1))
|
||||
self.connect((self.blocks_multiply_const_vxx_0, 0), (self.audio_sink_0_0, 0))
|
||||
self.connect((self.blocks_multiply_xx_0_0, 0), (self.blocks_complex_to_float_1, 0))
|
||||
self.connect((self.blocks_udp_source_0, 0), (self.digital_constellation_modulator_0, 0))
|
||||
self.connect((self.digital_constellation_modulator_0, 0), (self.blocks_multiply_xx_0_0, 0))
|
||||
|
||||
|
||||
def get_resamprate(self):
|
||||
return self.resamprate
|
||||
|
||||
def set_resamprate(self, resamprate):
|
||||
self.resamprate = resamprate
|
||||
|
||||
def get_samp_rate(self):
|
||||
return self.samp_rate
|
||||
|
||||
def set_samp_rate(self, samp_rate):
|
||||
self.samp_rate = samp_rate
|
||||
self.analog_sig_source_x_0_0_0.set_sampling_freq(self.samp_rate)
|
||||
|
||||
def get_sps(self):
|
||||
return self.sps
|
||||
|
||||
def set_sps(self, sps):
|
||||
self.sps = sps
|
||||
|
||||
def get_nfilts(self):
|
||||
return self.nfilts
|
||||
|
||||
def set_nfilts(self, nfilts):
|
||||
self.nfilts = nfilts
|
||||
|
||||
def get_mixf(self):
|
||||
return self.mixf
|
||||
|
||||
def set_mixf(self, mixf):
|
||||
self.mixf = mixf
|
||||
self.analog_sig_source_x_0_0_0.set_frequency(self.mixf)
|
||||
|
||||
|
||||
|
||||
|
||||
def argument_parser():
|
||||
description = 'requires GNU Radio 3.8xxx'
|
||||
parser = ArgumentParser(description=description)
|
||||
parser.add_argument(
|
||||
"-r", "--resamprate", dest="resamprate", type=intx, default=24,
|
||||
help="Set resamprate [default=%(default)r]")
|
||||
parser.add_argument(
|
||||
"-s", "--samp-rate", dest="samp_rate", type=intx, default=48000,
|
||||
help="Set samp_rate [default=%(default)r]")
|
||||
return parser
|
||||
|
||||
|
||||
def main(top_block_cls=tx_8psk, options=None):
|
||||
if options is None:
|
||||
options = argument_parser().parse_args()
|
||||
tb = top_block_cls(resamprate=options.resamprate, samp_rate=options.samp_rate)
|
||||
|
||||
def sig_handler(sig=None, frame=None):
|
||||
tb.stop()
|
||||
tb.wait()
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
signal.signal(signal.SIGINT, sig_handler)
|
||||
signal.signal(signal.SIGTERM, sig_handler)
|
||||
|
||||
tb.start()
|
||||
|
||||
tb.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
|
||||
</configuration>
|
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 220 B |
Before Width: | Height: | Size: 440 B |
Before Width: | Height: | Size: 660 B |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 880 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |