This commit is contained in:
Kurt Moraw 2020-10-27 16:41:16 +01:00
parent 647db711c4
commit 3deb0a09fd
514 changed files with 242695 additions and 2 deletions

View File

@ -1,2 +1,61 @@
# SSB_HighSpeed_Modem # QO-100-modem
8PSK/QPSK Modem to send Images/Data via a 2,7kHz SSB channel in high speed 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.
# Prerequisites
* LINUX Desktop PC ... working
* Raspberry PI 4 ... working
* Raspberry PI 3B+ ... working, but not 100% error free in fullduplex mode (RX only or TX only is working)
* Odroid N2 ... working
* Odroid C2 ... working
* Odroid C4 ... working
* GNU Radio Version 3.8.x.
* Raspberry: Raspian OS ist NOT working, instead Ubuntu 64bit is required
* Application Software "oscardata.exe" running on Windows, Linux, (possibly MAC-OS, not tested)
# building the software
1. go into the folder "modem"
2. run "make"
# starting the modem and application
1. go into the folder "modem"
2. run the software: ./qo100modem
command line parameters:
no parameter ... normal usage
-m IP ... specify the V4 IP adress of the device where the application software is running. This is useful if you have more than one qo100modem running simultaneously. Without this parameter the app will search the modem automatically.
-e 1 ... do NOT start the GNU Radio files automatically. This is useful if you want to work on the GR Flowgraphs and want to start it manually.
3. start the user application on any PC in your home network. It will find the modem automatically
The file is located in QO-100-modem/oscardata/oscardata/bin/Release
On windows just start oscardata.exe
On Linux start it with: mono oscardata.exe
# tested scenarious
* QO-100 via IC-9700, IC-7300 or IC-7100 ... working
* Short Wave 6m band via IC-7300, IC-7100 ... working. In case of significant noise, use the lowest bit rate (3000 bit/s)
# usage
In the IC-9700 activate the DATA mode and the RX filter FIL1 to full range of 3.6kHz.
In oscardata.exe go to the "BER" tab. Then click START. If you change the bitrate, wait a few seconds before starting again.
The program is now sending test data frames to the default sound card. If your sound card is properly connected to the transceiver then switch the transceiver to TX and the data will be sent to QO-100.
Receive your transmission, feed it to the default soundcard. As soon as oscardata.exe detects a correct data frame it will display status messages on the screen.
(For testing purposes you can just connect Line-Out of your soundcard with Line-IN with a cable.)
To assign the soundcard to the modem I recommend to use pavucontrol. Using the TX volume set a signal level of about 20 to 24 dB over noise floor. You will need about -10dB compared to the BPSK400 beacon. The received audio volume can be adjusted with help of the spectrum display in oscardata.exe-
Now as the transmission is OK, you can go to the "Image RX/TX" tab. First, select a picture quality then load a picture and finally press SEND to send it to QO-100. When you correctly receive your own transmission the RX picture will be displayed line by line.
vy 73, DJ0ABR

919
grc/8psk_rx.grc Normal file
View File

@ -0,0 +1,919 @@
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: rx_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: [16, 12.0]
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: [1112, 12.0]
rotation: 0
state: enabled
- name: outputsps
id: variable
parameters:
comment: 'Samples/Symbol
fixed value,
do not change.
Used to adjust
bitrate vs. bandwidth'
value: '7'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [40, 180.0]
rotation: 0
state: enabled
- name: rrc_taps
id: variable
parameters:
comment: ''
value: firdes.root_raised_cosine(nfilts, nfilts, 1.1/float(sps), 0.2, 11*sps*nfilts)
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1184, 12.0]
rotation: 0
state: enabled
- name: sps
id: variable
parameters:
comment: 'Samples/Symbol
fixed value,
do not change'
value: '4'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [488, 12.0]
rotation: 0
state: enabled
- name: analog_agc2_xx_0_0
id: analog_agc2_xx
parameters:
affinity: ''
alias: ''
attack_rate: 1e-2
comment: Costas loop needs AGC (loop gain depends on input level)
decay_rate: '0.2'
gain: '2'
max_gain: '3'
maxoutbuf: '0'
minoutbuf: '0'
reference: '1'
type: complex
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [400, 620.0]
rotation: 0
state: enabled
- name: analog_const_source_x_0
id: analog_const_source_x
parameters:
affinity: ''
alias: ''
comment: 'Marker to find the start
of the values'
const: '1000'
maxoutbuf: '0'
minoutbuf: '0'
type: int
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [472, 916.0]
rotation: 180
state: true
- name: analog_const_source_x_0_0
id: analog_const_source_x
parameters:
affinity: ''
alias: ''
comment: 'Marker to find the start
of the values'
const: '1000'
maxoutbuf: '0'
minoutbuf: '0'
type: int
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [536, 1076.0]
rotation: 180
state: true
- name: analog_const_source_x_0_1
id: analog_const_source_x
parameters:
affinity: ''
alias: ''
comment: ''
const: '16777216'
maxoutbuf: '0'
minoutbuf: '0'
type: float
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [792, 1044.0]
rotation: 180
state: true
- 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 frinal signal.
Use it als for RX in the reverse direction'
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: [592, 76.0]
rotation: 0
state: enabled
- name: audio_source_0
id: audio_source
parameters:
affinity: ''
alias: ''
comment: get audio from transceiver
device_name: ''
maxoutbuf: '0'
minoutbuf: '0'
num_outputs: '1'
ok_to_block: 'True'
samp_rate: samp_rate
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1384, 364.0]
rotation: 180
state: true
- name: blocks_complex_to_float_0
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: [824, 1160.0]
rotation: 180
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: [816, 104.0]
rotation: 0
state: enabled
- name: blocks_float_to_complex_0
id: blocks_float_to_complex
parameters:
affinity: ''
alias: ''
comment: 'combile I and Q
to complex signal'
maxoutbuf: '0'
minoutbuf: '0'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [552, 336.0]
rotation: 180
state: true
- name: blocks_float_to_int_0
id: blocks_float_to_int
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
scale: '16777216'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [632, 1156.0]
rotation: 180
state: true
- name: blocks_float_to_int_0_0
id: blocks_float_to_int
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
scale: '16777216'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [632, 1204.0]
rotation: 180
state: true
- name: blocks_float_to_int_0_1
id: blocks_float_to_int
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
scale: '1'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [520, 1012.0]
rotation: 180
state: true
- name: blocks_interleave_0
id: blocks_interleave
parameters:
affinity: ''
alias: ''
blocksize: '1'
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
num_streams: '2'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [360, 1000.0]
rotation: 180
state: true
- name: blocks_interleave_0_0
id: blocks_interleave
parameters:
affinity: ''
alias: ''
blocksize: '1'
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
num_streams: '3'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [328, 1128.0]
rotation: 180
state: true
- name: blocks_multiply_xx_0_0_0
id: blocks_multiply_xx
parameters:
affinity: ''
alias: ''
comment: make I
maxoutbuf: '0'
minoutbuf: '0'
num_inputs: '2'
type: float
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [744, 304.0]
rotation: 180
state: enabled
- name: blocks_multiply_xx_0_1
id: blocks_multiply_xx
parameters:
affinity: ''
alias: ''
comment: make Q
maxoutbuf: '0'
minoutbuf: '0'
num_inputs: '2'
type: float
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [808, 400.0]
rotation: 180
state: enabled
- name: blocks_multiply_xx_0_1_0
id: blocks_multiply_xx
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
num_inputs: '2'
type: float
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [648, 984.0]
rotation: 180
state: enabled
- name: blocks_udp_sink_0
id: blocks_udp_sink
parameters:
affinity: ''
alias: ''
comment: 'send RX data to UDP
port 1235 on the local machine'
eof: 'False'
ipaddr: 127.0.0.1
port: '40135'
psize: '344'
type: byte
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1272, 516.0]
rotation: 0
state: true
- name: blocks_udp_sink_0_0
id: blocks_udp_sink
parameters:
affinity: ''
alias: ''
comment: 'send QPSK Constellation data to UDP
port 1236 on the local machine'
eof: 'False'
ipaddr: 127.0.0.1
port: '40136'
psize: '120'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [72, 1004.0]
rotation: 180
state: enabled
- name: blocks_udp_sink_0_0_0
id: blocks_udp_sink
parameters:
affinity: ''
alias: ''
comment: 'send QPSK Constellation data to UDP
port 1236 on the local machine'
eof: 'False'
ipaddr: 127.0.0.1
port: '40137'
psize: '120'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [72, 1132.0]
rotation: 180
state: enabled
- name: digital_constellation_decoder_cb_0
id: digital_constellation_decoder_cb
parameters:
affinity: ''
alias: ''
comment: '8PSK decoding, same
parameters as modulator'
constellation: digital.constellation_8psk_natural().base()
maxoutbuf: '0'
minoutbuf: '0'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [824, 540.0]
rotation: 0
state: enabled
- name: digital_costas_loop_cc_0
id: digital_costas_loop_cc
parameters:
affinity: ''
alias: ''
comment: 'locks the signal and
converts into baseband'
maxoutbuf: '0'
minoutbuf: '0'
order: '8'
use_snr: 'False'
w: '0.15'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [584, 528.0]
rotation: 0
state: enabled
- name: digital_diff_decoder_bb_0
id: digital_diff_decoder_bb
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
modulus: '8'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1048, 540.0]
rotation: 0
state: enabled
- name: digital_lms_dd_equalizer_cc_0
id: digital_lms_dd_equalizer_cc
parameters:
affinity: ''
alias: ''
cnst: digital.constellation_8psk_natural().base()
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
mu: '0.01'
num_taps: '15'
sps: outputsps
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [304, 468.0]
rotation: 0
state: enabled
- name: digital_pfb_clock_sync_xxx_0
id: digital_pfb_clock_sync_xxx
parameters:
affinity: ''
alias: ''
comment: 'synchronize the Clock,
works very well with drifting
QO-100 signal'
filter_size: nfilts
init_phase: nfilts/16
loop_bw: '0.06'
max_dev: '2'
maxoutbuf: '0'
minoutbuf: '0'
osps: outputsps
sps: sps
taps: rrc_taps
type: ccf
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [80, 556.0]
rotation: 0
state: enabled
- name: low_pass_filter_0
id: low_pass_filter
parameters:
affinity: ''
alias: ''
beta: '6.76'
comment: 'Anti-Aliasing filter
Level correction
and decimation'
cutoff_freq: '3900'
decim: '1'
gain: '12'
interp: '1'
maxoutbuf: '0'
minoutbuf: '0'
samp_rate: samp_rate
type: fir_filter_fff
width: '3300'
win: firdes.WIN_HAMMING
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1048, 316.0]
rotation: 180
state: enabled
- name: mmse_resampler_xx_0
id: mmse_resampler_xx
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
phase_shift: '0'
resamp_ratio: resamp
type: complex
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [136, 352.0]
rotation: 180
state: true
- name: mmse_resampler_xx_0_0
id: mmse_resampler_xx
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
phase_shift: '0'
resamp_ratio: samp_rate / 8000
type: float
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [776, 904.0]
rotation: 180
state: true
- name: qtgui_const_sink_x_0
id: qtgui_const_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: '"red"'
color2: '"red"'
color3: '"red"'
color4: '"red"'
color5: '"red"'
color6: '"red"'
color7: '"red"'
color8: '"red"'
color9: '"red"'
comment: ''
grid: 'False'
gui_hint: ''
label1: ''
label10: ''
label2: ''
label3: ''
label4: ''
label5: ''
label6: ''
label7: ''
label8: ''
label9: ''
legend: 'True'
marker1: '0'
marker10: '0'
marker2: '0'
marker3: '0'
marker4: '0'
marker5: '0'
marker6: '0'
marker7: '0'
marker8: '0'
marker9: '0'
name: '""'
nconnections: '1'
size: '1024'
style1: '0'
style10: '0'
style2: '0'
style3: '0'
style4: '0'
style5: '0'
style6: '0'
style7: '0'
style8: '0'
style9: '0'
tr_chan: '0'
tr_level: '0.0'
tr_mode: qtgui.TRIG_MODE_FREE
tr_slope: qtgui.TRIG_SLOPE_POS
tr_tag: '""'
type: complex
update_time: '0.10'
width1: '1'
width10: '1'
width2: '1'
width3: '1'
width4: '1'
width5: '1'
width6: '1'
width7: '1'
width8: '1'
width9: '1'
xmax: '2'
xmin: '-2'
ymax: '2'
ymin: '-2'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [824, 756.0]
rotation: 0
state: disabled
- name: qtgui_const_sink_x_0_0
id: qtgui_const_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: '"red"'
color2: '"red"'
color3: '"red"'
color4: '"red"'
color5: '"red"'
color6: '"red"'
color7: '"red"'
color8: '"red"'
color9: '"red"'
comment: ''
grid: 'False'
gui_hint: ''
label1: ''
label10: ''
label2: ''
label3: ''
label4: ''
label5: ''
label6: ''
label7: ''
label8: ''
label9: ''
legend: 'True'
marker1: '0'
marker10: '0'
marker2: '0'
marker3: '0'
marker4: '0'
marker5: '0'
marker6: '0'
marker7: '0'
marker8: '0'
marker9: '0'
name: '""'
nconnections: '1'
size: '1024'
style1: '0'
style10: '0'
style2: '0'
style3: '0'
style4: '0'
style5: '0'
style6: '0'
style7: '0'
style8: '0'
style9: '0'
tr_chan: '0'
tr_level: '0.0'
tr_mode: qtgui.TRIG_MODE_FREE
tr_slope: qtgui.TRIG_SLOPE_POS
tr_tag: '""'
type: complex
update_time: '0.10'
width1: '1'
width10: '1'
width2: '1'
width3: '1'
width4: '1'
width5: '1'
width6: '1'
width7: '1'
width8: '1'
width9: '1'
xmax: '2'
xmin: '-2'
ymax: '2'
ymin: '-2'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [864, 628.0]
rotation: 0
state: disabled
- name: resamp
id: parameter
parameters:
alias: ''
comment: "Resampling Rate\nfrom Audio Rate\nto 8kS/s which is\nthe input of the\
\ \nPolypashe Clock"
hide: none
label: resamp
short_id: r
type: intx
value: '6'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [328, 156.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: [200, 156.0]
rotation: 0
state: true
connections:
- [analog_agc2_xx_0_0, '0', digital_costas_loop_cc_0, '0']
- [analog_const_source_x_0, '0', blocks_interleave_0, '0']
- [analog_const_source_x_0_0, '0', blocks_interleave_0_0, '0']
- [analog_const_source_x_0_1, '0', blocks_multiply_xx_0_1_0, '1']
- [analog_sig_source_x_0_0_0, '0', blocks_complex_to_float_1, '0']
- [audio_source_0, '0', low_pass_filter_0, '0']
- [audio_source_0, '0', mmse_resampler_xx_0_0, '0']
- [blocks_complex_to_float_0, '0', blocks_float_to_int_0, '0']
- [blocks_complex_to_float_0, '1', blocks_float_to_int_0_0, '0']
- [blocks_complex_to_float_1, '0', blocks_multiply_xx_0_1, '1']
- [blocks_complex_to_float_1, '1', blocks_multiply_xx_0_0_0, '1']
- [blocks_float_to_complex_0, '0', mmse_resampler_xx_0, '0']
- [blocks_float_to_int_0, '0', blocks_interleave_0_0, '1']
- [blocks_float_to_int_0_0, '0', blocks_interleave_0_0, '2']
- [blocks_float_to_int_0_1, '0', blocks_interleave_0, '1']
- [blocks_interleave_0, '0', blocks_udp_sink_0_0, '0']
- [blocks_interleave_0_0, '0', blocks_udp_sink_0_0_0, '0']
- [blocks_multiply_xx_0_0_0, '0', blocks_float_to_complex_0, '0']
- [blocks_multiply_xx_0_1, '0', blocks_float_to_complex_0, '1']
- [blocks_multiply_xx_0_1_0, '0', blocks_float_to_int_0_1, '0']
- [digital_constellation_decoder_cb_0, '0', digital_diff_decoder_bb_0, '0']
- [digital_costas_loop_cc_0, '0', blocks_complex_to_float_0, '0']
- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0']
- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_0, '0']
- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_0_0, '0']
- [digital_diff_decoder_bb_0, '0', blocks_udp_sink_0, '0']
- [digital_lms_dd_equalizer_cc_0, '0', analog_agc2_xx_0_0, '0']
- [digital_pfb_clock_sync_xxx_0, '0', digital_lms_dd_equalizer_cc_0, '0']
- [low_pass_filter_0, '0', blocks_multiply_xx_0_0_0, '0']
- [low_pass_filter_0, '0', blocks_multiply_xx_0_1, '0']
- [mmse_resampler_xx_0, '0', digital_pfb_clock_sync_xxx_0, '0']
- [mmse_resampler_xx_0_0, '0', blocks_multiply_xx_0_1_0, '0']
metadata:
file_format: 1

391
grc/8psk_tx.grc Normal file
View File

@ -0,0 +1,391 @@
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

View File

@ -0,0 +1,973 @@
options:
parameters:
author: DJ0ABR
category: '[GRC Hier Blocks]'
cmake_opt: ''
comment: 'send and receive a datastream
with 3500 bit/s via a QO-100
SSB channel with 2700 Hz bandwidth
works with Gnu Radio 3.8.xxx ONLY
does not work with 3.7.x'
copyright: ''
description: works with Gnu Radio 3.8.xxx
gen_cmake: 'Off'
gen_linking: dynamic
generate_options: no_gui
hier_block_src_path: '.:'
id: qpsk_rx
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 RX-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: [328, 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: [704, 12.0]
rotation: 0
state: enabled
- name: outputsps
id: variable
parameters:
comment: 'Samples/Symbol
fixed value,
do not change.
Used to adjust
bitrate vs. bandwidth'
value: '7'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [8, 212.0]
rotation: 0
state: enabled
- name: qpsk__constellation
id: variable_constellation_rect
parameters:
comment: ''
const_points: '[0.707+0.707j, -0.707+0.707j, -0.707-0.707j, 0.707-0.707j]'
imag_sect: '2'
precision: '8'
real_sect: '2'
rot_sym: '4'
soft_dec_lut: '''auto'''
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: [976, 12.0]
rotation: 0
state: enabled
- name: sps
id: variable
parameters:
comment: 'Resampling Rate
of the Polyphase
Clock Sync and its filter'
value: '4'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [568, 12.0]
rotation: 0
state: enabled
- name: analog_agc2_xx_0_0
id: analog_agc2_xx
parameters:
affinity: ''
alias: ''
attack_rate: '0.01'
comment: 'Costas loop needs AGC
loop gain depends on input level'
decay_rate: '0.2'
gain: '1'
max_gain: '3'
maxoutbuf: '0'
minoutbuf: '0'
reference: '1'
type: complex
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [544, 636.0]
rotation: 0
state: enabled
- name: analog_const_source_x_0
id: analog_const_source_x
parameters:
affinity: ''
alias: ''
comment: 'Marker to find the start
of the values'
const: '1000'
maxoutbuf: '0'
minoutbuf: '0'
type: int
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [464, 788.0]
rotation: 180
state: true
- name: analog_const_source_x_0_0
id: analog_const_source_x
parameters:
affinity: ''
alias: ''
comment: 'Marker to find the start
of the values'
const: '1000'
maxoutbuf: '0'
minoutbuf: '0'
type: int
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [536, 948.0]
rotation: 180
state: true
- name: analog_const_source_x_0_0_0
id: analog_const_source_x
parameters:
affinity: ''
alias: ''
comment: 'Marker to find the start
of the values'
const: '0'
maxoutbuf: '0'
minoutbuf: '0'
type: float
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [824, 1140.0]
rotation: 180
state: disabled
- name: analog_const_source_x_0_1
id: analog_const_source_x
parameters:
affinity: ''
alias: ''
comment: ''
const: '16777216'
maxoutbuf: '0'
minoutbuf: '0'
type: float
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [792, 916.0]
rotation: 180
state: true
- 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 frinal signal.
Use it als for RX in the reverse direction'
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: [200, 220.0]
rotation: 0
state: enabled
- name: analog_sig_source_x_1
id: analog_sig_source_x
parameters:
affinity: ''
alias: ''
amp: '1'
comment: "Markers for the \nFrequ.Sink"
freq: '1500'
maxoutbuf: '0'
minoutbuf: '0'
offset: '0'
phase: '0'
samp_rate: samp_rate
type: float
waveform: analog.GR_COS_WAVE
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [712, 140.0]
rotation: 0
state: disabled
- name: analog_sig_source_x_1_0
id: analog_sig_source_x
parameters:
affinity: ''
alias: ''
amp: '1'
comment: ''
freq: '3000'
maxoutbuf: '0'
minoutbuf: '0'
offset: '0'
phase: '0'
samp_rate: samp_rate
type: float
waveform: analog.GR_COS_WAVE
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [704, 300.0]
rotation: 0
state: disabled
- name: audio_source_0
id: audio_source
parameters:
affinity: ''
alias: ''
comment: get audio from transceiver
device_name: ''
maxoutbuf: '0'
minoutbuf: '0'
num_outputs: '1'
ok_to_block: 'True'
samp_rate: samp_rate
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1328, 468.0]
rotation: 180
state: true
- name: blocks_complex_to_float_0
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: [824, 1032.0]
rotation: 180
state: enabled
- 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: [456, 248.0]
rotation: 0
state: enabled
- name: blocks_float_to_complex_0
id: blocks_float_to_complex
parameters:
affinity: ''
alias: ''
comment: 'combile I and Q
to complex signal'
maxoutbuf: '0'
minoutbuf: '0'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [320, 464.0]
rotation: 180
state: enabled
- name: blocks_float_to_int_0
id: blocks_float_to_int
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
scale: '16777216'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [632, 1028.0]
rotation: 180
state: true
- name: blocks_float_to_int_0_0
id: blocks_float_to_int
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
scale: '16777216'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [632, 1076.0]
rotation: 180
state: true
- name: blocks_float_to_int_0_1
id: blocks_float_to_int
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
scale: '1'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [512, 868.0]
rotation: 180
state: true
- name: blocks_interleave_0
id: blocks_interleave
parameters:
affinity: ''
alias: ''
blocksize: '1'
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
num_streams: '2'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [360, 872.0]
rotation: 180
state: true
- name: blocks_interleave_0_0
id: blocks_interleave
parameters:
affinity: ''
alias: ''
blocksize: '1'
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
num_streams: '3'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [320, 1000.0]
rotation: 180
state: true
- name: blocks_multiply_xx_0_0_0
id: blocks_multiply_xx
parameters:
affinity: ''
alias: ''
comment: make I
maxoutbuf: '0'
minoutbuf: '0'
num_inputs: '2'
type: float
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [520, 408.0]
rotation: 180
state: enabled
- name: blocks_multiply_xx_0_1
id: blocks_multiply_xx
parameters:
affinity: ''
alias: ''
comment: make Q
maxoutbuf: '0'
minoutbuf: '0'
num_inputs: '2'
type: float
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [560, 512.0]
rotation: 180
state: enabled
- name: blocks_multiply_xx_0_1_0
id: blocks_multiply_xx
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
num_inputs: '2'
type: float
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [640, 856.0]
rotation: 180
state: enabled
- name: blocks_udp_sink_0
id: blocks_udp_sink
parameters:
affinity: ''
alias: ''
comment: 'send RX data to UDP
port 1235 on the local machine'
eof: 'False'
ipaddr: 127.0.0.1
port: '40135'
psize: '344'
type: byte
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1240, 588.0]
rotation: 0
state: true
- name: blocks_udp_sink_0_0
id: blocks_udp_sink
parameters:
affinity: ''
alias: ''
comment: 'send QPSK Constellation data to UDP
port 1236 on the local machine'
eof: 'False'
ipaddr: 127.0.0.1
port: '40136'
psize: '120'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [64, 860.0]
rotation: 180
state: enabled
- name: blocks_udp_sink_0_0_0
id: blocks_udp_sink
parameters:
affinity: ''
alias: ''
comment: 'send QPSK Constellation data to UDP
port 1236 on the local machine'
eof: 'False'
ipaddr: 127.0.0.1
port: '40137'
psize: '120'
type: int
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [64, 988.0]
rotation: 180
state: enabled
- name: digital_constellation_decoder_cb_0
id: digital_constellation_decoder_cb
parameters:
affinity: ''
alias: ''
comment: 'QPSK decoding, same
parameters as modulator'
constellation: qpsk__constellation
maxoutbuf: '0'
minoutbuf: '0'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [992, 612.0]
rotation: 0
state: enabled
- name: digital_costas_loop_cc_0
id: digital_costas_loop_cc
parameters:
affinity: ''
alias: ''
comment: 'locks the signal and
converts into baseband'
maxoutbuf: '0'
minoutbuf: '0'
order: '4'
use_snr: 'False'
w: '0.06'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [744, 616.0]
rotation: 0
state: enabled
- name: digital_lms_dd_equalizer_cc_0
id: digital_lms_dd_equalizer_cc
parameters:
affinity: ''
alias: ''
cnst: qpsk__constellation
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
mu: '0.01'
num_taps: '15'
sps: outputsps
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [288, 628.0]
rotation: 0
state: enabled
- name: digital_pfb_clock_sync_xxx_0
id: digital_pfb_clock_sync_xxx
parameters:
affinity: ''
alias: ''
comment: 'synchronize the Clock,
works very well with drifting
QO-100 signal'
filter_size: nfilts
init_phase: nfilts/2
loop_bw: '0.1'
max_dev: '1.5'
maxoutbuf: '0'
minoutbuf: '0'
osps: outputsps
sps: sps
taps: firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), 0.35, 11*sps*nfilts)
type: ccf
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [64, 652.0]
rotation: 0
state: enabled
- name: low_pass_filter_0
id: low_pass_filter
parameters:
affinity: ''
alias: ''
beta: '6.76'
comment: 'Anti-Aliasing filter
Level correction
and decimation'
cutoff_freq: '3500'
decim: '1'
gain: '8'
interp: '1'
maxoutbuf: '0'
minoutbuf: '0'
samp_rate: samp_rate
type: fir_filter_fff
width: '3100'
win: firdes.WIN_HAMMING
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [1048, 412.0]
rotation: 180
state: enabled
- name: mmse_resampler_xx_0
id: mmse_resampler_xx
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
phase_shift: '0'
resamp_ratio: samp_rate / 8000
type: float
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [776, 768.0]
rotation: 180
state: true
- name: mmse_resampler_xx_1
id: mmse_resampler_xx
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
phase_shift: '0'
resamp_ratio: resamp
type: complex
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [72, 480.0]
rotation: 180
state: true
- name: qtgui_const_sink_x_0
id: qtgui_const_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: '"red"'
color2: '"red"'
color3: '"red"'
color4: '"red"'
color5: '"red"'
color6: '"red"'
color7: '"red"'
color8: '"red"'
color9: '"red"'
comment: ''
grid: 'False'
gui_hint: ''
label1: ''
label10: ''
label2: ''
label3: ''
label4: ''
label5: ''
label6: ''
label7: ''
label8: ''
label9: ''
legend: 'True'
marker1: '0'
marker10: '0'
marker2: '0'
marker3: '0'
marker4: '0'
marker5: '0'
marker6: '0'
marker7: '0'
marker8: '0'
marker9: '0'
name: '""'
nconnections: '2'
size: '1024'
style1: '0'
style10: '0'
style2: '0'
style3: '0'
style4: '0'
style5: '0'
style6: '0'
style7: '0'
style8: '0'
style9: '0'
tr_chan: '0'
tr_level: '0.0'
tr_mode: qtgui.TRIG_MODE_FREE
tr_slope: qtgui.TRIG_SLOPE_POS
tr_tag: '""'
type: complex
update_time: '0.10'
width1: '1'
width10: '1'
width2: '1'
width3: '1'
width4: '1'
width5: '1'
width6: '1'
width7: '1'
width8: '1'
width9: '1'
xmax: '2'
xmin: '-2'
ymax: '2'
ymin: '-2'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [768, 532.0]
rotation: 180
state: disabled
- name: qtgui_freq_sink_x_1
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: '1.0'
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: '4096'
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: TX / RX Spectrum
nconnections: '3'
showports: 'False'
tr_chan: '0'
tr_level: '0.0'
tr_mode: qtgui.TRIG_MODE_FREE
tr_tag: '""'
type: float
units: dB
update_time: '.1'
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: [992, 208.0]
rotation: 0
state: disabled
- name: resamp
id: parameter
parameters:
alias: ''
comment: "Resampling Rate\nfrom Audio Rate\nto 8kS/s which is\nthe input of the\
\ \nPolypashe Clock"
hide: none
label: resamp
short_id: r
type: intx
value: '5'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [464, 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: [216, 12.0]
rotation: 0
state: true
connections:
- [analog_agc2_xx_0_0, '0', digital_costas_loop_cc_0, '0']
- [analog_const_source_x_0, '0', blocks_interleave_0, '0']
- [analog_const_source_x_0_0, '0', blocks_interleave_0_0, '0']
- [analog_const_source_x_0_0_0, '0', blocks_float_to_int_0_0, '0']
- [analog_const_source_x_0_1, '0', blocks_multiply_xx_0_1_0, '1']
- [analog_sig_source_x_0_0_0, '0', blocks_complex_to_float_1, '0']
- [analog_sig_source_x_1, '0', qtgui_freq_sink_x_1, '1']
- [analog_sig_source_x_1_0, '0', qtgui_freq_sink_x_1, '2']
- [audio_source_0, '0', low_pass_filter_0, '0']
- [audio_source_0, '0', mmse_resampler_xx_0, '0']
- [blocks_complex_to_float_0, '0', blocks_float_to_int_0, '0']
- [blocks_complex_to_float_0, '1', blocks_float_to_int_0_0, '0']
- [blocks_complex_to_float_1, '0', blocks_multiply_xx_0_1, '1']
- [blocks_complex_to_float_1, '1', blocks_multiply_xx_0_0_0, '1']
- [blocks_float_to_complex_0, '0', mmse_resampler_xx_1, '0']
- [blocks_float_to_int_0, '0', blocks_interleave_0_0, '1']
- [blocks_float_to_int_0_0, '0', blocks_interleave_0_0, '2']
- [blocks_float_to_int_0_1, '0', blocks_interleave_0, '1']
- [blocks_interleave_0, '0', blocks_udp_sink_0_0, '0']
- [blocks_interleave_0_0, '0', blocks_udp_sink_0_0_0, '0']
- [blocks_multiply_xx_0_0_0, '0', blocks_float_to_complex_0, '0']
- [blocks_multiply_xx_0_1, '0', blocks_float_to_complex_0, '1']
- [blocks_multiply_xx_0_1_0, '0', blocks_float_to_int_0_1, '0']
- [digital_constellation_decoder_cb_0, '0', blocks_udp_sink_0, '0']
- [digital_costas_loop_cc_0, '0', blocks_complex_to_float_0, '0']
- [digital_costas_loop_cc_0, '0', digital_constellation_decoder_cb_0, '0']
- [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_0, '0']
- [digital_lms_dd_equalizer_cc_0, '0', analog_agc2_xx_0_0, '0']
- [digital_lms_dd_equalizer_cc_0, '0', qtgui_const_sink_x_0, '1']
- [digital_pfb_clock_sync_xxx_0, '0', digital_lms_dd_equalizer_cc_0, '0']
- [low_pass_filter_0, '0', blocks_multiply_xx_0_0_0, '0']
- [low_pass_filter_0, '0', blocks_multiply_xx_0_1, '0']
- [low_pass_filter_0, '0', qtgui_freq_sink_x_1, '0']
- [mmse_resampler_xx_0, '0', blocks_multiply_xx_0_1_0, '0']
- [mmse_resampler_xx_1, '0', digital_pfb_clock_sync_xxx_0, '0']
metadata:
file_format: 1

View File

@ -0,0 +1,383 @@
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
images/readme.txt Normal file
View File

@ -0,0 +1 @@
Images are available here:

13
modem/Makefile Normal file
View File

@ -0,0 +1,13 @@
CFLAGS=-O3 -Wall
LDLIBS= -L. -lpthread -lfftw3 -lm -lzip
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
all: qo100modem
qo100modem: $(OBJ)
$(CC) -g -o $@ $^ $(LDFLAGS) $(LDLIBS)
clean:
rm -f *.o qo100modem

225
modem/arraysend.c Normal file
View File

@ -0,0 +1,225 @@
/*
* 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"
int AddHeader(uint8_t *data, int len, char *filename);
uint8_t *zipArray(uint8_t *data, int length, int *ziplen);
#define ZIPPED
#define TXMAXSIZE 200000
uint8_t TXarray[TXMAXSIZE];
int txlen; // total length of TXarray
int txpos; // current position in TXarray
uint8_t txtype = 0; // file type (from GUI)
uint8_t filestat = 0; // 0=first frame, 1=next frame, 2=last frame
/*
* start sending a named byte array
* data ... contents of the Byte array
* length ... length of the Byte array
* type ... type of the file (see statics)
* filename ... description of the file or its name which is send with the data
*/
int arraySend(uint8_t *data, int length, uint8_t type, char *filename)
{
if((length+55) >= TXMAXSIZE)
{
printf("file TOO long. Max is %d byte\n",TXMAXSIZE);
return 0;
}
txtype = type;
txpos = 0;
filestat = 0;
// if it is an ASCII, HTML or binary file, zip it
if(type == 3 || type == 4 || type == 5)
{
#ifdef ZIPPED
int ziplen = 0;
printf("orig len:%d\n",length);
uint8_t *zipdata = zipArray(data,length,&ziplen);
if(zipdata==NULL) return 0;
printf("zipped len:%d\n",ziplen);
// add a file header and copy to txdata for transmission
txlen = AddHeader(zipdata,ziplen,filename);
#else
txlen = AddHeader(data,length,filename);
#endif
printf("txlen:%d\n",txlen);
}
else
{
// add a file header and copy to txdata for transmission
txlen = AddHeader(data,length,filename);
}
// marker, we are sending
setSending(1);
return 1;
}
int AddHeader(uint8_t *data, int len, char *filename)
{
// make a unique ID number for this file
// we simply calc the CRC16 of the filename
uint16_t fncrc = Crc16_messagecalc(CRC16FILE, (uint8_t *)filename,strlen(filename));
// create the file header
// 50 bytes ... Filename (or first 50 chars of the filename)
// 2 bytes .... CRC16 od the filename, this is used as a file ID
// 3 bytes .... size of file
int flen = strlen(filename);
if (flen > 50) flen = 50;
memcpy(TXarray,filename,flen);
TXarray[50] = (uint8_t)((fncrc >> 8)&0xff);
TXarray[51] = (uint8_t)(fncrc&0xff);
TXarray[52] = len >> 16;
TXarray[53] = len >> 8;
TXarray[54] = len;
memcpy(TXarray+55,data,len);
return len+55;
}
// called from main() in a loop
// sends an array if specified by arraySend(..)
void doArraySend()
{
if(getSending() == 0) return;
if(filestat == 0)
{
// send first frame
printf("Start Array Send %d\n",getSending());
toGR_Preamble();
if(txlen <= PAYLOADLEN)
{
// we just need to send one frame
printf("send last frame only\n");
toGR_sendData(TXarray, txtype, 3);
toGR_sendData(TXarray, txtype, 3);
setSending(0);
}
else
{
printf("send first frame\n");
// data is longer than one PAYLOAD
toGR_sendData(TXarray, txtype, filestat);
txpos += PAYLOADLEN;
filestat = 1;
}
return;
}
if(filestat == 1)
{
// check if this is the last frame
int restlen = txlen - txpos;
if(restlen <= PAYLOADLEN)
{
// send as the last frame
printf("send last frame\n");
toGR_sendData(TXarray+txpos, txtype, 2);
toGR_sendData(TXarray+txpos, txtype, 2);
setSending(0); // transmission complete
}
else
{
// additional frame follows
printf("send next frame\n");
// from txdata send one chunk of length PAYLOADLEN
toGR_sendData(TXarray+txpos, txtype, filestat);
txpos += PAYLOADLEN;
}
return;
}
}
// make _arraySending flag thread safe
// it is called from main() and from udp-RX
pthread_mutex_t as_crit_sec;
#define AS_LOCK pthread_mutex_lock(&as_crit_sec)
#define AS_UNLOCK pthread_mutex_unlock(&as_crit_sec)
int __arraySending = 0; // 1 ... Array transmission in progress
void setSending(uint8_t onoff)
{
AS_LOCK;
__arraySending = onoff;
AS_UNLOCK;
}
int getSending()
{
int as;
AS_LOCK;
if(__arraySending != 0)
printf("__arraySending: %d\n",__arraySending);
as = __arraySending;
AS_UNLOCK;
return as;
}
#define defaultTXzipFN "tmp.zip"
uint8_t *zipArray(uint8_t *data, int length, int *ziplen)
{
int err = 0;
unlink(defaultTXzipFN); // delete existing zip file
struct zip *zp = zip_open(defaultTXzipFN, ZIP_CREATE, &err);
zip_source_t *s;
if ((s=zip_source_buffer(zp, data, length, 0)) == NULL ||
zip_file_add(zp, "my2databuffer", s, ZIP_FL_ENC_UTF_8) < 0)
{
zip_source_free(s);
printf("error adding file: %s\n", zip_strerror(zp));
return NULL;
}
zip_close(zp);
// zip file is done
// now read the file and return the buffer
#define TXMAXSIZE 200000
static uint8_t ZIPdata[TXMAXSIZE];
FILE *fp=fopen(defaultTXzipFN,"rb");
if(fp)
{
*ziplen = fread(ZIPdata,1,TXMAXSIZE,fp);
fclose(fp);
return ZIPdata;
}
return NULL;
}

170
modem/constellation.c Normal file
View File

@ -0,0 +1,170 @@
/*
* 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"
// functions for non-differential QPSK
// depending on the phase shift rotate a data blocks constellation
//uint8_t headerbytes[HEADERLEN] = {0x53, 0xe1, 0xa6};
// corresponds to these QPSK symbols:
// bits: 01010011 11100001 10100110
// syms: 1 1 0 3 3 2 0 1 2 2 1 2
uint8_t rxbytebuf[UDPBLOCKLEN+100]; // +100 ... reserve, just to be sure
uint8_t *convertQPSKSymToBytes(uint8_t *rxsymbols)
{
int sidx = 0;
for(int i=0; i<UDPBLOCKLEN; i++)
{
rxbytebuf[i] = rxsymbols[sidx++] << (bitsPerSymbol*3);
rxbytebuf[i] |= rxsymbols[sidx++] << (bitsPerSymbol*2);
rxbytebuf[i] |= rxsymbols[sidx++] << (bitsPerSymbol*1);
rxbytebuf[i] |= rxsymbols[sidx++] << (bitsPerSymbol*0);
}
return rxbytebuf;
}
void convertBytesToSyms_QPSK(uint8_t *bytes, uint8_t *syms, int bytenum)
{
unsigned int symidx = 0;
for(int i=0; i<bytenum; i++)
{
syms[symidx++] = (bytes[i] >> 6) & 3;
syms[symidx++] = (bytes[i] >> 4) & 3;
syms[symidx++] = (bytes[i] >> 2) & 3;
syms[symidx++] = (bytes[i] >> 0) & 3;
}
}
void rotateQPSKsyms(uint8_t *src, uint8_t *dst, int len)
{
for(int i=0; i<len; i++)
{
dst[i] = src[i] + 4;
dst[i]++;
dst[i] %= 4;
}
}
uint8_t QPSK_backbuf[UDPBLOCKLEN*8/2];
uint8_t *rotateBackQPSK(uint8_t *buf, int len, int rotations)
{
memcpy(QPSK_backbuf,buf,len);
for(unsigned int i=0; i<(unsigned int)len; i++)
{
for(int r=0; r<rotations; r++)
{
QPSK_backbuf[i] += 4;
QPSK_backbuf[i]--;
QPSK_backbuf[i] %= 4;
}
}
return QPSK_backbuf;
}
// works ONLY if number of bytes is a multiple of 3 !!!
void convertBytesToSyms_8PSK(uint8_t *bytes, uint8_t *syms, int bytenum)
{
unsigned int symidx = 0;
for(int i=0; i<bytenum; i+=3)
{
// convert next 3 bytes to 8 syms
syms[symidx++] = (bytes[0+i] >> 5) & 7;
syms[symidx++] = (bytes[0+i] >> 2) & 7;
syms[symidx++] = ((bytes[0+i] & 3) << 1) | ((bytes[1+i] >> 7) & 1);
syms[symidx++] = (bytes[1+i] >> 4) & 7;
syms[symidx++] = (bytes[1+i] >> 1) & 7;
syms[symidx++] = ((bytes[1+i] & 1) << 2) | ((bytes[2+i] >> 6) & 3);
syms[symidx++] = (bytes[2+i] >> 3) & 7;
syms[symidx++] = bytes[2+i] & 7;
}
}
void rotate8PSKsyms(uint8_t *src, uint8_t *dst, int len)
{
for(int i=0; i<len; i++)
{
dst[i] = src[i] + 8;
dst[i]++;
dst[i] %= 8;
}
}
uint8_t _8PSK_backbuf[UDPBLOCKLEN*8/3];
uint8_t *rotateBack8PSK(uint8_t *buf, int len, int rotations)
{
memcpy(_8PSK_backbuf,buf,len);
for(int i=0; i<len; i++)
{
for(int r=0; r<rotations; r++)
{
_8PSK_backbuf[i] += 8;
_8PSK_backbuf[i]--;
_8PSK_backbuf[i] %= 8;
}
}
return _8PSK_backbuf;
}
uint8_t *convert8PSKSymToBytes(uint8_t *rxsymbols, int len)
{
int sidx = 0;
// works ONLY if total frame length is a multiple of 3 !
for(int i=0; i<len; i+=3)
{
rxbytebuf[i] = rxsymbols[sidx++] << 5;
rxbytebuf[i] |= rxsymbols[sidx++] << 2;
rxbytebuf[i] |= rxsymbols[sidx] >> 1;
rxbytebuf[i+1] = rxsymbols[sidx++] << 7;
rxbytebuf[i+1] |= rxsymbols[sidx++] << 4;
rxbytebuf[i+1] |= rxsymbols[sidx++] << 1;
rxbytebuf[i+1] |= rxsymbols[sidx] >> 2;
rxbytebuf[i+2] = rxsymbols[sidx++] << 6;
rxbytebuf[i+2] |= rxsymbols[sidx++] << 3;
rxbytebuf[i+2] |= rxsymbols[sidx++];
}
return rxbytebuf;
}
void shiftleft(uint8_t *data, int shiftnum, int len)
{
for(int j=0; j<shiftnum; j++)
{
int b1=0,b2=0;
for(int i=len-1; i>=0; i--)
{
b1 = (data[i] & 0x80)>>7;
data[i] <<= 1;
data[i] |= b2;
b2 = b1;
}
}
}

83
modem/crc16.c Normal file
View File

@ -0,0 +1,83 @@
/*
* 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"
// since we use a static crc register we need TWO separated registers
// for RX and TX to get it thread safe, no.2 is for file ID generation
uint16_t reg16[3] = {0xffff,0xffff}; // shift register
uint16_t Crc16_bytecalc(int rxtx, uint8_t byt)
{
uint16_t polynom = 0x8408; // generator polynom
for (int i = 0; i < 8; ++i)
{
if ((reg16[rxtx] & 1) != (byt & 1))
reg16[rxtx] = (uint16_t)((reg16[rxtx] >> 1) ^ polynom);
else
reg16[rxtx] >>= 1;
byt >>= 1;
}
return reg16[rxtx];
}
uint16_t Crc16_messagecalc(int rxtx, uint8_t *data,int len)
{
reg16[rxtx] = 0xffff;
for (int i = 0; i < len; i++)
reg16[rxtx] = Crc16_bytecalc(rxtx,data[i]);
return reg16[rxtx];
}
// =================================================================
uint32_t reg32[2] = {0xffffffff,0xffffffff}; // Shiftregister
void crc32_bytecalc(int rxtx, unsigned char byte)
{
int i;
uint32_t polynom = 0xEDB88320; // Generatorpolynom
for (i=0; i<8; ++i)
{
if ((reg32[rxtx]&1) != (byte&1))
reg32[rxtx] = (reg32[rxtx]>>1)^polynom;
else
reg32[rxtx] >>= 1;
byte >>= 1;
}
}
uint32_t crc32_messagecalc(int rxtx, unsigned char *data, int len)
{
int i;
reg32[rxtx] = 0xffffffff;
for(i=0; i<len; i++) {
crc32_bytecalc(rxtx,data[i]);
}
return reg32[rxtx] ^ 0xffffffff;
}

116
modem/fec.c Normal file
View File

@ -0,0 +1,116 @@
/*
* 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 <cstddef>
#include <iostream>
#include <string>
#include "fec/schifra_galois_field.hpp"
#include "fec/schifra_galois_field_polynomial.hpp"
#include "fec/schifra_sequential_root_generator_polynomial_creator.hpp"
#include "fec/schifra_reed_solomon_encoder.hpp"
#include "fec/schifra_reed_solomon_decoder.hpp"
#include "fec/schifra_reed_solomon_block.hpp"
#include "fec/schifra_error_processes.hpp"
/* Finite Field Parameters */
const std::size_t field_descriptor = 8;
const std::size_t generator_polynomial_index = 120;
const std::size_t generator_polynomial_root_count = FECLEN;
/* Reed Solomon Code Parameters */
const std::size_t code_length = FECBLOCKLEN;
const std::size_t fec_length = FECLEN;
const std::size_t data_length = code_length - fec_length;
/* Instantiate Finite Field and Generator Polynomials */
const schifra::galois::field field(field_descriptor,
schifra::galois::primitive_polynomial_size06,
schifra::galois::primitive_polynomial06);
schifra::galois::field_polynomial generator_polynomial(field);
/* Instantiate Encoder and Decoder (Codec) */
typedef schifra::reed_solomon::encoder<code_length,fec_length,data_length> encoder_t;
typedef schifra::reed_solomon::decoder<code_length,fec_length,data_length> decoder_t;
int cfec_Reconstruct(uint8_t *darr, uint8_t *destination)
{
schifra::reed_solomon::block<code_length,fec_length> rxblock;
for(std::size_t i=0; i<code_length; i++)
rxblock.data[i] = darr[i];
const decoder_t decoder(field, generator_polynomial_index);
if (!decoder.decode(rxblock))
{
// FEC decoding not possible
return 0;
}
for(std::size_t i=0; i<data_length; i++)
destination[i] = rxblock[i];
return 1;
}
void GetFEC(uint8_t *txblock, int len, uint8_t *destArray)
{
schifra::reed_solomon::block<code_length,fec_length> block;
// fill payload into an FEC-block
for(std::size_t i=0; i<data_length; i++)
block.data[i] = txblock[i];
/* Transform message into Reed-Solomon encoded codeword */
const encoder_t encoder(field, generator_polynomial);
if (!encoder.encode(block))
{
// encoding not possible, should never happen
return;
}
// get result out of the FEC block
for(std::size_t i=0; i<code_length; i++)
destArray[i] = block[i];
}
void initFEC()
{
if (!schifra::make_sequential_root_generator_polynomial( field,
generator_polynomial_index,
generator_polynomial_root_count,
generator_polynomial))
{
std::cout << "Error - Failed to create sequential root generator!" << std::endl;
return;
}
}

115
modem/fec.h Normal file
View File

@ -0,0 +1,115 @@
#pragma once
/**
* zfec -- fast forward error correction library with Python interface
* https://tahoe-lafs.org/trac/zfec/
This package implements an "erasure code", or "forward error correction code".
You may use this package under the GNU General Public License, version 2 or, at your option, any later version.
*/
#include <stddef.h>
typedef unsigned char gf;
typedef struct {
unsigned long magic;
unsigned short k, n; /* parameters of the code */
gf* enc_matrix;
} fec_t;
#if defined(_MSC_VER)
// actually, some of the flavors (i.e. Enterprise) do support restrict
//#define restrict __restrict
#define restrict
#endif
/**
* param k the number of blocks required to reconstruct
* param m the total number of blocks created
*/
fec_t* fec_new(unsigned short k, unsigned short m);
void fec_free(fec_t* p);
/**
* @param inpkts the "primary blocks" i.e. the chunks of the input data
* @param fecs buffers into which the secondary blocks will be written
* @param block_nums the numbers of the desired check blocks (the id >= k) which fec_encode() will produce and store into the buffers of the fecs parameter
* @param num_block_nums the length of the block_nums array
* @param sz size of a packet in bytes
*/
void fec_encode(const fec_t* code, const gf** src, gf** fecs, size_t sz);
/**
* @param inpkts an array of packets (size k); If a primary block, i, is present then it must be at index i. Secondary blocks can appear anywhere.
* @param outpkts an array of buffers into which the reconstructed output packets will be written (only packets which are not present in the inpkts input will be reconstructed and written to outpkts)
* @param index an array of the blocknums of the packets in inpkts
* @param sz size of a packet in bytes
*/
void fec_decode(const fec_t* code, const gf** inpkts, gf** outpkts, const unsigned* index, size_t sz);
#if defined(_MSC_VER)
#define alloca _alloca
#else
#ifdef __GNUC__
#ifndef alloca
#define alloca(x) __builtin_alloca(x)
#endif
#else
#include <alloca.h>
#endif
#endif
/**
* zfec -- fast forward error correction library with Python interface
*
* Copyright (C) 2007-2008 Allmydata, Inc.
* Author: Zooko Wilcox-O'Hearn
*
* This file is part of zfec.
*
* See README.rst for licensing information.
*/
/*
* Much of this work is derived from the "fec" software by Luigi Rizzo, et
* al., the copyright notice and licence terms of which are included below
* for reference.
*
* fec.h -- forward error correction based on Vandermonde matrices
* 980614
* (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
*
* Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
* Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
*
* Modifications by Dan Rubenstein (see Modifications.txt for
* their description.
* Modifications (C) 1998 Dan Rubenstein (drubenst@cs.umass.edu)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/

172
modem/fec/schifra_crc.hpp Normal file
View File

@ -0,0 +1,172 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_CRC_HPP
#define INCLUDE_SCHIFRA_CRC_HPP
#include <iostream>
#include <string>
namespace schifra
{
class crc32
{
public:
typedef std::size_t crc32_t;
crc32(const crc32_t& _key, const crc32_t& _state = 0x00)
: key(_key),
state(_state),
initial_state(_state)
{
initialize_crc32_table();
}
void reset()
{
state = initial_state;
}
void update_1byte(const unsigned char data)
{
state = (state >> 8) ^ table[data];
}
void update(const unsigned char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(data[i]);
}
}
void update(char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::string& data)
{
for (std::size_t i = 0; i < data.size(); ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::size_t& data)
{
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
}
crc32_t crc()
{
return state;
}
private:
crc32& operator=(const crc32&);
void initialize_crc32_table()
{
for (std::size_t i = 0; i < 0xFF; ++i)
{
crc32_t reg = i;
for (int j = 0; j < 0x08; ++j)
{
reg = ((reg & 1) ? (reg >> 1) ^ key : reg >> 1);
}
table[i] = reg;
}
}
protected:
crc32_t key;
crc32_t state;
const crc32_t initial_state;
crc32_t table[256];
};
class schifra_crc : public crc32
{
public:
schifra_crc(const crc32_t _key)
: crc32(_key,0xAAAAAAAA)
{}
void update(const unsigned char& data)
{
state = ((state >> 8) ^ table[data]) ^ ((state << 8) ^ table[~data]);
}
void update(const unsigned char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(data[i]);
}
}
void update(const char data[], const std::size_t& count)
{
for (std::size_t i = 0; i < count; ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::string& data)
{
for (std::size_t i = 0; i < data.size(); ++i)
{
update_1byte(static_cast<unsigned char>(data[i]));
}
}
void update(const std::size_t& data)
{
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
}
};
} // namespace schifra
#endif

View File

@ -0,0 +1,109 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ECC_TRAITS_HPP
#define INCLUDE_SCHIFRA_ECC_TRAITS_HPP
namespace schifra
{
namespace traits
{
template <std::size_t code_length> struct symbol;
/* bits per symbol */
template <> struct symbol< 3> { enum {size = 2}; };
template <> struct symbol< 7> { enum {size = 3}; };
template <> struct symbol< 15> { enum {size = 4}; };
template <> struct symbol< 31> { enum {size = 5}; };
template <> struct symbol< 63> { enum {size = 6}; };
template <> struct symbol< 127> { enum {size = 7}; };
template <> struct symbol< 255> { enum {size = 8}; };
template <> struct symbol< 511> { enum {size = 9}; };
template <> struct symbol< 1023> { enum {size = 10}; };
template <> struct symbol< 2047> { enum {size = 11}; };
template <> struct symbol< 4195> { enum {size = 12}; };
template <> struct symbol< 8191> { enum {size = 13}; };
template <> struct symbol<16383> { enum {size = 14}; };
template <> struct symbol<32768> { enum {size = 15}; };
template <> struct symbol<65535> { enum {size = 16}; };
/* Credits: Modern C++ Design - Andrei Alexandrescu */
template <bool> class __static_assert__
{
public:
__static_assert__(...) {}
};
template <> class __static_assert__<true> {};
template <> class __static_assert__<false>;
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
struct validate_reed_solomon_code_parameters
{
private:
__static_assert__<(code_length > 0)> assertion1;
__static_assert__<(code_length > fec_length)> assertion2;
__static_assert__<(code_length > data_length)> assertion3;
__static_assert__<(code_length == fec_length + data_length)> assertion4;
};
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
struct validate_reed_solomon_block_parameters
{
private:
__static_assert__<(code_length > 0)> assertion1;
__static_assert__<(code_length > fec_length)> assertion2;
__static_assert__<(code_length > data_length)> assertion3;
__static_assert__<(code_length == fec_length + data_length)> assertion4;
};
template <typename Encoder, typename Decoder>
struct equivalent_encoder_decoder
{
private:
__static_assert__<(Encoder::trait::code_length == Decoder::trait::code_length)> assertion1;
__static_assert__<(Encoder::trait::fec_length == Decoder::trait::fec_length) > assertion2;
__static_assert__<(Encoder::trait::data_length == Decoder::trait::data_length)> assertion3;
};
template <std::size_t code_length_, std::size_t fec_length_, std::size_t data_length_ = code_length_ - fec_length_>
class reed_solomon_triat
{
public:
typedef validate_reed_solomon_code_parameters<code_length_,fec_length_,data_length_> vrscp;
enum { code_length = code_length_ };
enum { fec_length = fec_length_ };
enum { data_length = data_length_ };
};
}
} // namespace schifra
#endif

View File

@ -0,0 +1,256 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
#define INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t block_length, std::size_t fec_length>
inline void interleaved_stack_erasure_mapper(const std::vector<std::size_t>& missing_row_index,
std::vector<erasure_locations_t>& erasure_row_list)
{
erasure_row_list.resize(block_length);
for (std::size_t i = 0; i < block_length; ++i)
{
erasure_row_list[i].reserve(fec_length);
}
for (std::size_t i = 0; i < missing_row_index.size(); ++i)
{
for (std::size_t j = 0; j < block_length; ++j)
{
erasure_row_list[j].push_back(missing_row_index[i]);
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_encode(const encoder<code_length,fec_length>& encoder,
block<code_length,fec_length> (&output)[code_length])
{
for (std::size_t i = 0; i < code_length; ++i)
{
if (!encoder.encode(output[i]))
{
std::cout << "erasure_channel_stack_encode() - Error: Failed to encode block[" << i <<"]" << std::endl;
return false;
}
}
interleave<code_length,fec_length>(output);
return true;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class erasure_code_decoder : public decoder<code_length,fec_length,data_length>
{
public:
typedef decoder<code_length,fec_length,data_length> decoder_type;
typedef typename decoder_type::block_type block_type;
typedef std::vector<galois::field_polynomial> polynomial_list_type;
erasure_code_decoder(const galois::field& gfield,
const unsigned int& gen_initial_index)
: decoder<code_length,fec_length,data_length>(gfield, gen_initial_index)
{
for (std::size_t i = 0; i < code_length; ++i)
{
received_.push_back(galois::field_polynomial(decoder_type::field_, code_length - 1));
syndrome_.push_back(galois::field_polynomial(decoder_type::field_));
}
};
bool decode(block_type rsblock[code_length], const erasure_locations_t& erasure_list) const
{
if (
(!decoder_type::decoder_valid_) ||
(erasure_list.size() != fec_length)
)
{
return false;
}
for (std::size_t i = 0; i < code_length; ++i)
{
decoder_type::load_message (received_[i], rsblock [i]);
decoder_type::compute_syndrome(received_[i], syndrome_[i]);
}
erasure_locations_t erasure_locations;
decoder_type::prepare_erasure_list(erasure_locations,erasure_list);
galois::field_polynomial gamma(galois::field_element(decoder_type::field_, 1));
decoder_type::compute_gamma(gamma,erasure_locations);
std::vector<int> gamma_roots;
find_roots_in_data(gamma,gamma_roots);
polynomial_list_type omega;
for (std::size_t i = 0; i < code_length; ++i)
{
omega.push_back((gamma * syndrome_[i]) % fec_length);
}
galois::field_polynomial gamma_derivative = gamma.derivative();
for (std::size_t i = 0; i < gamma_roots.size(); ++i)
{
int error_location = static_cast<int>(gamma_roots[i]);
galois::field_symbol alpha_inverse = decoder_type::field_.alpha(error_location);
galois::field_element denominator = gamma_derivative(alpha_inverse);
if (denominator == 0)
{
return false;
}
for (std::size_t j = 0; j < code_length; ++j)
{
galois::field_element numerator = (omega[j](alpha_inverse) * decoder_type::root_exponent_table_[error_location]);
/*
A minor optimization can be made in the event the
numerator is equal to zero by not executing the
following line.
*/
rsblock[j][error_location - 1] ^= decoder_type::field_.div(numerator.poly(),denominator.poly());
}
}
return true;
}
private:
void find_roots_in_data(const galois::field_polynomial& poly, std::vector<int>& root_list) const
{
/*
Chien Search, as described in parent, but only
for locations within the data range of the message.
*/
root_list.reserve(fec_length << 1);
root_list.resize(0);
std::size_t polynomial_degree = poly.deg();
std::size_t root_list_size = 0;
for (int i = 1; i <= static_cast<int>(data_length); ++i)
{
if (0 == poly(decoder_type::field_.alpha(i)).poly())
{
root_list.push_back(i);
root_list_size++;
if (root_list_size == polynomial_degree)
{
break;
}
}
}
}
mutable polynomial_list_type received_;
mutable polynomial_list_type syndrome_;
};
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_decode(const decoder<code_length,fec_length>& general_decoder,
const erasure_locations_t& missing_row_index,
block<code_length,fec_length> (&output)[code_length])
{
if (missing_row_index.empty())
{
return true;
}
interleave<code_length,fec_length>(output);
for (std::size_t i = 0; i < code_length; ++i)
{
if (!general_decoder.decode(output[i],missing_row_index))
{
std::cout << "[2] erasure_channel_stack_decode() - Error: Failed to decode block[" << i <<"]" << std::endl;
return false;
}
}
return true;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool erasure_channel_stack_decode(const erasure_code_decoder<code_length,fec_length>& erasure_decoder,
const erasure_locations_t& missing_row_index,
block<code_length,fec_length> (&output)[code_length])
{
/*
Note: 1. Missing row indicies must be unique.
2. Missing row indicies must exist within
the stack's size.
3. There will be NO errors in the rows (aka output)
4. The information members of the blocks will
not be utilized.
There are NO exceptions to these rules!
*/
if (missing_row_index.empty())
{
return true;
}
else if (missing_row_index.size() == fec_length)
{
interleave<code_length,fec_length>(output);
return erasure_decoder.decode(output,missing_row_index);
}
else
return erasure_channel_stack_decode<code_length,fec_length>(
static_cast<const decoder<code_length,fec_length>&>(erasure_decoder),
missing_row_index,
output);
}
} // namespace reed_solomon
} // namepsace schifra
#endif

View File

@ -0,0 +1,602 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
#define INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <deque>
#include <vector>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
template <std::size_t code_length, std::size_t fec_length>
inline void add_erasure_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0xFF; // Or one can simply equate to zero
}
template <std::size_t code_length, std::size_t fec_length>
inline void add_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0xFF;
}
template <std::size_t code_length, std::size_t fec_length>
inline void add_error_4bit_symbol(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
{
block[position] = (~block[position]) & 0x0F;
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors00(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
{
add_error((start_position + scale * i) % code_length,rsblock);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_wth_mask(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const int& mask,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
{
std::size_t position = (start_position + scale * i) % code_length;
rsblock[position] = (~rsblock[position]) & mask;
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
for (std::size_t i = 0; i < error_count; ++i)
{
add_error((start_position + scale * i) % code_length,rsblock);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_erasures00(reed_solomon::block<code_length,fec_length>& rsblock,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
for (std::size_t i = 0; i < fec_length; ++i)
{
std::size_t error_position = (start_position + scale * i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t erasure_count,
const std::size_t& start_position,
const std::size_t& scale = 1)
{
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
for (std::size_t i = 0; i < erasure_count; ++i)
{
/* Note: Must make sure duplicate erasures are not added */
std::size_t error_position = (start_position + scale * i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
namespace error_mode
{
enum type
{
errors_erasures, // Errors first then erasures
erasures_errors // Erasures first then errors
};
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
const error_mode::type& mode,
const std::size_t& start_position,
const std::size_t& erasure_count,
reed_solomon::erasure_locations_t& erasure_list,
const std::size_t between_space = 0)
{
std::size_t error_count = (fec_length - erasure_count) >> 1;
if ((2 * error_count) + erasure_count > fec_length)
{
std::cout << "corrupt_message_errors_erasures() - ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
std::size_t error_position = 0;
switch (mode)
{
case error_mode::erasures_errors : {
for (std::size_t i = 0; i < erasure_count; ++i)
{
error_position = (start_position + i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
for (std::size_t i = 0; i < error_count; ++i)
{
error_position = (start_position + erasure_count + between_space + i) % code_length;
add_error(error_position,rsblock);
}
}
break;
case error_mode::errors_erasures : {
for (std::size_t i = 0; i < error_count; ++i)
{
error_position = (start_position + i) % code_length;
add_error(error_position,rsblock);
}
for (std::size_t i = 0; i < erasure_count; ++i)
{
error_position = (start_position + error_count + between_space + i) % code_length;
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
}
}
break;
}
for (std::size_t i = 0; i < code_length; ++i)
{
if (erasures[i] == 1) erasure_list.push_back(i);
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_interleaved_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& erasure_count,
reed_solomon::erasure_locations_t& erasure_list)
{
std::size_t error_count = (fec_length - erasure_count) >> 1;
if ((2 * error_count) + erasure_count > fec_length)
{
std::cout << "corrupt_message_interleaved_errors_erasures() - [1] ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
std::size_t erasures[code_length];
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
std::size_t e = 0;
std::size_t s = 0;
std::size_t i = 0;
while ((e < error_count) || (s < erasure_count) || (i < (error_count + erasure_count)))
{
std::size_t error_position = (start_position + i) % code_length;
if (((i & 0x01) == 0) && (s < erasure_count))
{
add_erasure_error(error_position,rsblock);
erasures[error_position] = 1;
s++;
}
else if (((i & 0x01) == 1) && (e < error_count))
{
e++;
add_error(error_position,rsblock);
}
++i;
}
for (std::size_t j = 0; j < code_length; ++j)
{
if (erasures[j] == 1) erasure_list.push_back(j);
}
if ((2 * e) + erasure_list.size() > fec_length)
{
std::cout << "corrupt_message_interleaved_errors_erasures() - [2] ERROR Too many erasures and errors!" << std::endl;
std::cout << "Error Count: " << error_count << std::endl;
std::cout << "Erasure Count: " << error_count << std::endl;
return;
}
}
namespace details
{
template <std::size_t code_length, std::size_t fec_length, bool t>
struct corrupt_message_all_errors_segmented_impl
{
static void process(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& distance_between_blocks = 1)
{
std::size_t block_1_error_count = (fec_length >> 2);
std::size_t block_2_error_count = (fec_length >> 1) - block_1_error_count;
for (std::size_t i = 0; i < block_1_error_count; ++i)
{
add_error((start_position + i) % code_length,rsblock);
}
std::size_t new_start_position = (start_position + (block_1_error_count)) + distance_between_blocks;
for (std::size_t i = 0; i < block_2_error_count; ++i)
{
add_error((new_start_position + i) % code_length,rsblock);
}
}
};
template <std::size_t code_length, std::size_t fec_length>
struct corrupt_message_all_errors_segmented_impl<code_length,fec_length,false>
{
static void process(reed_solomon::block<code_length,fec_length>&,
const std::size_t&, const std::size_t&)
{}
};
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_segmented(reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t& start_position,
const std::size_t& distance_between_blocks = 1)
{
details::corrupt_message_all_errors_segmented_impl<code_length,fec_length,(fec_length > 2)>::
process(rsblock,start_position,distance_between_blocks);
}
inline bool check_for_duplicate_erasures(const std::vector<int>& erasure_list)
{
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
for (std::size_t j = i + 1; j < erasure_list.size(); ++j)
{
if (erasure_list[i] == erasure_list[j])
{
return false;
}
}
}
return true;
}
inline void dump_erasure_list(const schifra::reed_solomon::erasure_locations_t& erasure_list)
{
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
std::cout << "[" << i << "," << erasure_list[i] << "] ";
}
std::cout << std::endl;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool is_block_equivelent(const reed_solomon::block<code_length,fec_length>& rsblock,
const std::string& data,
const bool display = false,
const bool all_errors = false)
{
std::string::const_iterator it = data.begin();
bool error_found = false;
for (std::size_t i = 0; i < code_length - fec_length; ++i, ++it)
{
if (static_cast<char>(rsblock.data[i] & 0xFF) != (*it))
{
error_found = true;
if (display)
{
printf("is_block_equivelent() - Error at loc : %02d\td1: %02X\td2: %02X\n",
static_cast<unsigned int>(i),
rsblock.data[i],
static_cast<unsigned char>(*it));
}
if (!all_errors)
return false;
}
}
return !error_found;
}
template <std::size_t code_length, std::size_t fec_length>
inline bool are_blocks_equivelent(const reed_solomon::block<code_length,fec_length>& block1,
const reed_solomon::block<code_length,fec_length>& block2,
const std::size_t span = code_length,
const bool display = false,
const bool all_errors = false)
{
bool error_found = false;
for (std::size_t i = 0; i < span; ++i)
{
if (block1[i] != block2[i])
{
error_found = true;
if (display)
{
printf("are_blocks_equivelent() - Error at loc : %02d\td1: %04X\td2: %04X\n",
static_cast<unsigned int>(i),
block1[i],
block2[i]);
}
if (!all_errors)
return false;
}
}
return !error_found;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline bool block_stacks_equivelent(const reed_solomon::block<code_length,fec_length> block_stack1[stack_size],
const reed_solomon::block<code_length,fec_length> block_stack2[stack_size])
{
for (std::size_t i = 0; i < stack_size; ++i)
{
if (!are_blocks_equivelent(block_stack1[i],block_stack2[i]))
{
return false;
}
}
return true;
}
template <std::size_t block_length, std::size_t stack_size>
inline bool block_stacks_equivelent(const reed_solomon::data_block<std::size_t,block_length> block_stack1[stack_size],
const reed_solomon::data_block<std::size_t,block_length> block_stack2[stack_size])
{
for (std::size_t i = 0; i < stack_size; ++i)
{
for (std::size_t j = 0; j < block_length; ++j)
{
if (block_stack1[i][j] != block_stack2[i][j])
{
return false;
}
}
}
return true;
}
inline void corrupt_file_with_burst_errors(const std::string& file_name,
const long& start_position,
const long& burst_length)
{
if (!schifra::fileio::file_exists(file_name))
{
std::cout << "corrupt_file() - Error: " << file_name << " does not exist!" << std::endl;
return;
}
if (static_cast<std::size_t>(start_position + burst_length) >= schifra::fileio::file_size(file_name))
{
std::cout << "corrupt_file() - Error: Burst error out of bounds." << std::endl;
return;
}
std::vector<char> data(burst_length);
std::ifstream ifile(file_name.c_str(), std::ios::in | std::ios::binary);
if (!ifile)
{
return;
}
ifile.seekg(start_position,std::ios_base::beg);
ifile.read(&data[0],burst_length);
ifile.close();
for (long i = 0; i < burst_length; ++i)
{
data[i] = ~data[i];
}
std::ofstream ofile(file_name.c_str(), std::ios::in | std::ios::out | std::ios::binary);
if (!ofile)
{
return;
}
ofile.seekp(start_position,std::ios_base::beg);
ofile.write(&data[0],burst_length);
ofile.close();
}
static const std::size_t global_random_error_index[] =
{
13, 170, 148, 66, 228, 208, 182, 92,
4, 137, 97, 99, 237, 151, 15, 0,
119, 243, 41, 222, 33, 211, 188, 5,
44, 30, 210, 111, 54, 79, 61, 223,
239, 149, 73, 115, 201, 234, 194, 62,
147, 70, 19, 49, 72, 52, 164, 29,
102, 225, 203, 153, 18, 205, 40, 217,
165, 177, 166, 134, 236, 68, 231, 154,
116, 136, 47, 240, 46, 89, 120, 183,
242, 28, 161, 226, 241, 230, 10, 131,
207, 132, 83, 171, 202, 195, 227, 206,
112, 88, 90, 146, 117, 180, 26, 78,
118, 254, 107, 110, 220, 7, 192, 187,
31, 175, 127, 209, 32, 12, 84, 128,
190, 156, 95, 105, 104, 246, 91, 215,
219, 142, 36, 186, 247, 233, 167, 133,
160, 16, 140, 169, 23, 96, 155, 235,
179, 76, 253, 103, 238, 67, 35, 121,
100, 27, 213, 58, 77, 248, 174, 39,
214, 56, 42, 200, 106, 21, 129, 114,
252, 113, 168, 53, 25, 216, 64, 232,
81, 75, 2, 224, 250, 60, 135, 204,
48, 196, 94, 63, 244, 191, 93, 126,
138, 159, 9, 85, 249, 34, 185, 163,
17, 65, 184, 82, 109, 172, 108, 69,
150, 3, 20, 221, 162, 212, 152, 59,
198, 74, 229, 55, 87, 178, 141, 199,
57, 130, 80, 173, 101, 122, 144, 51,
139, 11, 8, 125, 158, 124, 123, 37,
14, 24, 22, 43, 197, 50, 98, 6,
176, 251, 86, 218, 193, 71, 145, 1,
45, 38, 189, 143, 245, 157, 181
};
static const std::size_t error_index_size = sizeof(global_random_error_index) / sizeof(std::size_t);
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& error_index_start_position,
const bool display_positions = false)
{
schifra::reed_solomon::block<code_length,fec_length> tmp_rsblock = rsblock;
for (std::size_t i = 0; i < error_count; ++i)
{
std::size_t error_position = (global_random_error_index[(error_index_start_position + i) % error_index_size]) % code_length;
add_error(error_position,rsblock);
if (display_positions)
{
std::cout << "Error index: " << error_position << std::endl;
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
const std::size_t error_count,
const std::size_t& error_index_start_position,
const std::vector<std::size_t>& random_error_index,
const bool display_positions = false)
{
for (std::size_t i = 0; i < error_count; ++i)
{
std::size_t error_position = (random_error_index[(error_index_start_position + i) % random_error_index.size()]) % code_length;
add_error(error_position,rsblock);
if (display_positions)
{
std::cout << "Error index: " << error_position << std::endl;
}
}
}
inline void generate_error_index(const std::size_t index_size,
std::vector<std::size_t>& random_error_index,
std::size_t seed)
{
if (0 == seed)
{
seed = 0xA5A5A5A5;
}
::srand(static_cast<unsigned int>(seed));
std::deque<std::size_t> index_list;
for (std::size_t i = 0; i < index_size; ++i)
{
index_list.push_back(i);
}
random_error_index.reserve(index_size);
random_error_index.resize(0);
while (!index_list.empty())
{
// possibly the worst way of doing this.
std::size_t index = ::rand() % index_list.size();
random_error_index.push_back(index_list[index]);
index_list.erase(index_list.begin() + index);
}
}
} // namespace schifra
#endif

View File

@ -0,0 +1,227 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_FILEIO_HPP
#define INCLUDE_SCHIFRA_FILEIO_HPP
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>
#include "schifra_crc.hpp"
namespace schifra
{
namespace fileio
{
inline void read_into_vector(const std::string& file_name, std::vector<std::string>& buffer)
{
std::ifstream file(file_name.c_str());
if (!file) return;
std::string line;
while (std::getline(file,line))
{
buffer.push_back(line);
}
file.close();
}
inline void write_from_vector(const std::string& file_name, const std::vector<std::string>& buffer)
{
std::ofstream file(file_name.c_str());
if (!file) return;
std::ostream_iterator <std::string> os(file,"\n");
std::copy(buffer.begin(),buffer.end(), os);
file.close();
}
inline bool file_exists(const std::string& file_name)
{
std::ifstream file(file_name.c_str(), std::ios::binary);
return ((!file) ? false : true);
}
inline std::size_t file_size(const std::string& file_name)
{
std::ifstream file(file_name.c_str(),std::ios::binary);
if (!file) return 0;
file.seekg (0, std::ios::end);
return static_cast<std::size_t>(file.tellg());
}
inline void load_file(const std::string& file_name, std::string& buffer)
{
std::ifstream file(file_name.c_str(), std::ios::binary);
if (!file) return;
buffer.assign(std::istreambuf_iterator<char>(file),std::istreambuf_iterator<char>());
file.close();
}
inline void load_file(const std::string& file_name, char** buffer, std::size_t& buffer_size)
{
std::ifstream in_stream(file_name.c_str(),std::ios::binary);
if (!in_stream) return;
buffer_size = file_size(file_name);
*buffer = new char[buffer_size];
in_stream.read(*buffer,static_cast<std::streamsize>(buffer_size));
in_stream.close();
}
inline void write_file(const std::string& file_name, const std::string& buffer)
{
std::ofstream file(file_name.c_str(),std::ios::binary);
file << buffer;
file.close();
}
inline void write_file(const std::string& file_name, char* buffer, const std::size_t& buffer_size)
{
std::ofstream out_stream(file_name.c_str(),std::ios::binary);
if (!out_stream) return;
out_stream.write(buffer,static_cast<std::streamsize>(buffer_size));
out_stream.close();
}
inline bool copy_file(const std::string& src_file_name, const std::string& dest_file_name)
{
std::ifstream src_file(src_file_name.c_str(),std::ios::binary);
std::ofstream dest_file(dest_file_name.c_str(),std::ios::binary);
if (!src_file) return false;
if (!dest_file) return false;
const std::size_t block_size = 1024;
char buffer[block_size];
std::size_t remaining_bytes = file_size(src_file_name);
while (remaining_bytes >= block_size)
{
src_file.read(&buffer[0],static_cast<std::streamsize>(block_size));
dest_file.write(&buffer[0],static_cast<std::streamsize>(block_size));
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
src_file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
dest_file.write(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
remaining_bytes = 0;
}
src_file.close();
dest_file.close();
return true;
}
inline bool files_identical(const std::string& file_name1, const std::string& file_name2)
{
std::ifstream file1(file_name1.c_str(),std::ios::binary);
std::ifstream file2(file_name2.c_str(),std::ios::binary);
if (!file1) return false;
if (!file2) return false;
if (file_size(file_name1) != file_size(file_name2)) return false;
const std::size_t block_size = 1024;
char buffer1[block_size];
char buffer2[block_size];
std::size_t remaining_bytes = file_size(file_name1);
while (remaining_bytes >= block_size)
{
file1.read(&buffer1[0],static_cast<std::streamsize>(block_size));
file2.read(&buffer2[0],static_cast<std::streamsize>(block_size));
for (std::size_t i = 0; i < block_size; ++i)
{
if (buffer1[i] != buffer2[i])
{
return false;
}
}
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
file1.read(&buffer1[0],static_cast<std::streamsize>(remaining_bytes));
file2.read(&buffer2[0],static_cast<std::streamsize>(remaining_bytes));
for (std::size_t i = 0; i < remaining_bytes; ++i)
{
if (buffer1[i] != buffer2[i])
{
return false;
}
}
remaining_bytes = 0;
}
file1.close();
file2.close();
return true;
}
inline std::size_t file_crc(crc32& crc_module, const std::string& file_name)
{
std::ifstream file(file_name.c_str(),std::ios::binary);
if (!file) return 0;
const std::size_t block_size = 1024;
char buffer[block_size];
std::size_t remaining_bytes = file_size(file_name);
crc_module.reset();
while (remaining_bytes >= block_size)
{
file.read(&buffer[0],static_cast<std::streamsize>(block_size));
crc_module.update(buffer,block_size);
remaining_bytes -= block_size;
}
if (remaining_bytes > 0)
{
file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
crc_module.update(buffer,remaining_bytes);
remaining_bytes = 0;
}
return crc_module.crc();
}
} // namespace fileio
} // namespace schifra
#endif

View File

@ -0,0 +1,518 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
#include <algorithm>
#include <iostream>
#include <vector>
#include <limits>
#include <string>
namespace schifra
{
namespace galois
{
typedef int field_symbol;
const field_symbol GFERROR = -1;
class field
{
public:
field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly);
~field();
bool operator==(const field& gf) const;
bool operator!=(const field& gf) const;
inline field_symbol index(const field_symbol value) const
{
return index_of_[value];
}
inline field_symbol alpha(const field_symbol value) const
{
return alpha_to_[value];
}
inline unsigned int size() const
{
return field_size_;
}
inline unsigned int pwr() const
{
return power_;
}
inline unsigned int mask() const
{
return field_size_;
}
inline field_symbol add(const field_symbol& a, const field_symbol& b) const
{
return (a ^ b);
}
inline field_symbol sub(const field_symbol& a, const field_symbol& b) const
{
return (a ^ b);
}
inline field_symbol normalize(field_symbol x) const
{
while (x < 0)
{
x += static_cast<field_symbol>(field_size_);
}
while (x >= static_cast<field_symbol>(field_size_))
{
x -= static_cast<field_symbol>(field_size_);
x = (x >> power_) + (x & field_size_);
}
return x;
}
inline field_symbol mul(const field_symbol& a, const field_symbol& b) const
{
#if !defined(NO_GFLUT)
return mul_table_[a][b];
#else
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
#endif
}
inline field_symbol div(const field_symbol& a, const field_symbol& b) const
{
#if !defined(NO_GFLUT)
return div_table_[a][b];
#else
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
#endif
}
inline field_symbol exp(const field_symbol& a, int n) const
{
#if !defined(NO_GFLUT)
if (n >= 0)
return exp_table_[a][n & field_size_];
else
{
while (n < 0) n += field_size_;
return (n ? exp_table_[a][n] : 1);
}
#else
if (a != 0)
{
if (n < 0)
{
while (n < 0) n += field_size_;
return (n ? alpha_to_[normalize(index_of_[a] * n)] : 1);
}
else if (n)
return alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))];
else
return 1;
}
else
return 0;
#endif
}
#ifdef LINEAR_EXP_LUT
inline field_symbol* const linear_exp(const field_symbol& a) const
{
#if !defined(NO_GFLUT)
static const field_symbol upper_bound = 2 * field_size_;
if ((a >= 0) && (a <= upper_bound))
return linear_exp_table_[a];
else
return reinterpret_cast<field_symbol*>(0);
#else
return reinterpret_cast<field_symbol*>(0);
#endif
}
#endif
inline field_symbol inverse(const field_symbol& val) const
{
#if !defined(NO_GFLUT)
return mul_inverse_[val];
#else
return alpha_to_[normalize(field_size_ - index_of_[val])];
#endif
}
inline unsigned int prim_poly_term(const unsigned int index) const
{
return prim_poly_[index];
}
friend std::ostream& operator << (std::ostream& os, const field& gf);
private:
field();
field(const field& gfield);
field& operator=(const field& gfield);
void generate_field(const unsigned int* prim_poly_);
field_symbol gen_mul (const field_symbol& a, const field_symbol& b) const;
field_symbol gen_div (const field_symbol& a, const field_symbol& b) const;
field_symbol gen_exp (const field_symbol& a, const std::size_t& n) const;
field_symbol gen_inverse (const field_symbol& val) const;
std::size_t create_array(char buffer_[],
const std::size_t& length,
const std::size_t offset,
field_symbol** array);
std::size_t create_2d_array(char buffer_[],
std::size_t row_cnt, std::size_t col_cnt,
const std::size_t offset,
field_symbol*** array);
unsigned int power_;
std::size_t prim_poly_deg_;
unsigned int field_size_;
unsigned int prim_poly_hash_;
unsigned int* prim_poly_;
field_symbol* alpha_to_; // aka exponential or anti-log
field_symbol* index_of_; // aka log
field_symbol* mul_inverse_; // multiplicative inverse
field_symbol** mul_table_;
field_symbol** div_table_;
field_symbol** exp_table_;
field_symbol** linear_exp_table_;
char* buffer_;
};
inline field::field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly)
: power_(pwr),
prim_poly_deg_(primpoly_deg),
field_size_((1 << power_) - 1)
{
alpha_to_ = new field_symbol [field_size_ + 1];
index_of_ = new field_symbol [field_size_ + 1];
#if !defined(NO_GFLUT)
#ifdef LINEAR_EXP_LUT
static const std::size_t buffer_size = ((6 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
#else
static const std::size_t buffer_size = ((4 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
#endif
buffer_ = new char[buffer_size];
std::size_t offset = 0;
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&mul_table_);
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&div_table_);
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&exp_table_);
#ifdef LINEAR_EXP_LUT
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1) * 2,offset,&linear_exp_table_);
#else
linear_exp_table_ = 0;
#endif
offset = create_array(buffer_,(field_size_ + 1) * 2,offset,&mul_inverse_);
#else
buffer_ = 0;
mul_table_ = 0;
div_table_ = 0;
exp_table_ = 0;
mul_inverse_ = 0;
linear_exp_table_ = 0;
#endif
prim_poly_ = new unsigned int [prim_poly_deg_ + 1];
for (unsigned int i = 0; i < (prim_poly_deg_ + 1); ++i)
{
prim_poly_[i] = primitive_poly[i];
}
prim_poly_hash_ = 0xAAAAAAAA;
for (std::size_t i = 0; i < (prim_poly_deg_ + 1); ++i)
{
prim_poly_hash_ += ((i & 1) == 0) ? ( (prim_poly_hash_ << 7) ^ primitive_poly[i] * (prim_poly_hash_ >> 3)) :
(~((prim_poly_hash_ << 11) + (primitive_poly[i] ^ (prim_poly_hash_ >> 5))));
}
generate_field(primitive_poly);
}
inline field::~field()
{
if (0 != alpha_to_) { delete [] alpha_to_; alpha_to_ = 0; }
if (0 != index_of_) { delete [] index_of_; index_of_ = 0; }
if (0 != prim_poly_) { delete [] prim_poly_; prim_poly_ = 0; }
#if !defined(NO_GFLUT)
if (0 != mul_table_) { delete [] mul_table_; mul_table_ = 0; }
if (0 != div_table_) { delete [] div_table_; div_table_ = 0; }
if (0 != exp_table_) { delete [] exp_table_; exp_table_ = 0; }
#ifdef LINEAR_EXP_LUT
if (0 != linear_exp_table_) { delete [] linear_exp_table_; linear_exp_table_ = 0; }
#endif
if (0 != buffer_) { delete [] buffer_; buffer_ = 0; }
#endif
}
inline bool field::operator==(const field& gf) const
{
return (
(this->power_ == gf.power_) &&
(this->prim_poly_hash_ == gf.prim_poly_hash_)
);
}
inline bool field::operator!=(const field& gf) const
{
return !field::operator ==(gf);
}
inline void field::generate_field(const unsigned int* prim_poly)
{
/*
Note: It is assumed that the degree of the primitive
polynomial will be equivelent to the m value as
in GF(2^m)
*/
field_symbol mask = 1;
alpha_to_[power_] = 0;
for (field_symbol i = 0; i < static_cast<field_symbol>(power_); ++i)
{
alpha_to_[i] = mask;
index_of_[alpha_to_[i]] = i;
if (prim_poly[i] != 0)
{
alpha_to_[power_] ^= mask;
}
mask <<= 1;
}
index_of_[alpha_to_[power_]] = power_;
mask >>= 1;
for (field_symbol i = power_ + 1; i < static_cast<field_symbol>(field_size_); ++i)
{
if (alpha_to_[i - 1] >= mask)
alpha_to_[i] = alpha_to_[power_] ^ ((alpha_to_[i - 1] ^ mask) << 1);
else
alpha_to_[i] = alpha_to_[i - 1] << 1;
index_of_[alpha_to_[i]] = i;
}
index_of_[0] = GFERROR;
alpha_to_[field_size_] = 1;
#if !defined(NO_GFLUT)
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
for (field_symbol j = 0; j < static_cast<field_symbol>(field_size_ + 1); ++j)
{
mul_table_[i][j] = gen_mul(i,j);
div_table_[i][j] = gen_div(i,j);
exp_table_[i][j] = gen_exp(i,j);
}
}
#ifdef LINEAR_EXP_LUT
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
for (int j = 0; j < static_cast<field_symbol>(2 * field_size_); ++j)
{
linear_exp_table_[i][j] = gen_exp(i,j);
}
}
#endif
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
{
mul_inverse_[i] = gen_inverse(i);
mul_inverse_[i + (field_size_ + 1)] = mul_inverse_[i];
}
#endif
}
inline field_symbol field::gen_mul(const field_symbol& a, const field_symbol& b) const
{
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
}
inline field_symbol field::gen_div(const field_symbol& a, const field_symbol& b) const
{
if ((a == 0) || (b == 0))
return 0;
else
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
}
inline field_symbol field::gen_exp(const field_symbol& a, const std::size_t& n) const
{
if (a != 0)
return ((n == 0) ? 1 : alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))]);
else
return 0;
}
inline field_symbol field::gen_inverse(const field_symbol& val) const
{
return alpha_to_[normalize(field_size_ - index_of_[val])];
}
inline std::size_t field::create_array(char buffer[],
const std::size_t& length,
const std::size_t offset,
field_symbol** array)
{
const std::size_t row_size = length * sizeof(field_symbol);
(*array) = new(buffer + offset)field_symbol[length];
return row_size + offset;
}
inline std::size_t field::create_2d_array(char buffer[],
std::size_t row_cnt, std::size_t col_cnt,
const std::size_t offset,
field_symbol*** array)
{
const std::size_t row_size = col_cnt * sizeof(field_symbol);
char* buffer__offset = buffer + offset;
(*array) = new field_symbol* [row_cnt];
for (std::size_t i = 0; i < row_cnt; ++i)
{
(*array)[i] = new(buffer__offset + (i * row_size))field_symbol[col_cnt];
}
return (row_cnt * row_size) + offset;
}
inline std::ostream& operator << (std::ostream& os, const field& gf)
{
for (std::size_t i = 0; i < (gf.field_size_ + 1); ++i)
{
os << i << "\t" << gf.alpha_to_[i] << "\t" << gf.index_of_[i] << std::endl;
}
return os;
}
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 */
const unsigned int primitive_polynomial00[] = {1, 1, 0, 1};
const unsigned int primitive_polynomial_size00 = 4;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4*/
const unsigned int primitive_polynomial01[] = {1, 1, 0, 0, 1};
const unsigned int primitive_polynomial_size01 = 5;
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 1x^5 */
const unsigned int primitive_polynomial02[] = {1, 0, 1, 0, 0, 1};
const unsigned int primitive_polynomial_size02 = 6;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 */
const unsigned int primitive_polynomial03[] = {1, 1, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size03 = 7;
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 */
const unsigned int primitive_polynomial04[] = {1, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size04 = 8;
/* 1x^0 + 0x^1 + 1x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 1x^8 */
const unsigned int primitive_polynomial05[] = {1, 0, 1, 1, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size05 = 9;
/* 1x^0 + 1x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 + 1x^8 */
const unsigned int primitive_polynomial06[] = {1, 1, 1, 0, 0, 0, 0, 1, 1};
const unsigned int primitive_polynomial_size06 = 9;
/* 1x^0 + 0x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 1x^9 */
const unsigned int primitive_polynomial07[] = {1, 0, 0, 0, 1, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size07 = 10;
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 */
const unsigned int primitive_polynomial08[] = {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size08 = 11;
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 1x^11 */
const unsigned int primitive_polynomial09[] = {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size09 = 12;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 */
const unsigned int primitive_polynomial10[] = {1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size10 = 13;
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 1x^13 */
const unsigned int primitive_polynomial11[] = {1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size11 = 14;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 + 0x^11 + 0x^12 + 0x^13 + 1x^14 */
const unsigned int primitive_polynomial12[] = {1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size12 = 15;
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 0x^13 + 0x^14 + 1x^15 */
const unsigned int primitive_polynomial13[] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size13 = 16;
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 + 0x^13 + 0x^14 + 0x^15 + 1x^16 */
const unsigned int primitive_polynomial14[] = {1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1};
const unsigned int primitive_polynomial_size14 = 17;
} // namespace galois
} // namespace schifra
#endif

View File

@ -0,0 +1,277 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
#include <iostream>
#include <vector>
#include "schifra_galois_field.hpp"
namespace schifra
{
namespace galois
{
class field_element
{
public:
field_element(const field& gfield)
: field_(gfield),
poly_value_(-1)
{}
field_element(const field& gfield,const field_symbol& v)
: field_(const_cast<field&>(gfield)),
poly_value_(v)
{}
field_element(const field_element& gfe)
: field_(const_cast<field&>(gfe.field_)),
poly_value_(gfe.poly_value_)
{}
~field_element()
{}
inline field_element& operator = (const field_element& gfe)
{
if ((this != &gfe) && (&field_ == &gfe.field_))
{
poly_value_ = gfe.poly_value_;
}
return *this;
}
inline field_element& operator = (const field_symbol& v)
{
poly_value_ = v & field_.size();
return *this;
}
inline field_element& operator += (const field_element& gfe)
{
poly_value_ ^= gfe.poly_value_;
return *this;
}
inline field_element& operator += (const field_symbol& v)
{
poly_value_ ^= v;
return *this;
}
inline field_element& operator -= (const field_element& gfe)
{
*this += gfe;
return *this;
}
inline field_element& operator -= (const field_symbol& v)
{
*this += v;
return *this;
}
inline field_element& operator *= (const field_element& gfe)
{
poly_value_ = field_.mul(poly_value_, gfe.poly_value_);
return *this;
}
inline field_element& operator *= (const field_symbol& v)
{
poly_value_ = field_.mul(poly_value_, v);
return *this;
}
inline field_element& operator /= (const field_element& gfe)
{
poly_value_ = field_.div(poly_value_, gfe.poly_value_);
return *this;
}
inline field_element& operator /= (const field_symbol& v)
{
poly_value_ = field_.div(poly_value_, v);
return *this;
}
inline field_element& operator ^= (const int& n)
{
poly_value_ = field_.exp(poly_value_,n);
return *this;
}
inline bool operator == (const field_element& gfe) const
{
return ((field_ == gfe.field_) && (poly_value_ == gfe.poly_value_));
}
inline bool operator == (const field_symbol& v) const
{
return (poly_value_ == v);
}
inline bool operator != (const field_element& gfe) const
{
return ((field_ != gfe.field_) || (poly_value_ != gfe.poly_value_));
}
inline bool operator != (const field_symbol& v) const
{
return (poly_value_ != v);
}
inline bool operator < (const field_element& gfe)
{
return (poly_value_ < gfe.poly_value_);
}
inline bool operator < (const field_symbol& v)
{
return (poly_value_ < v);
}
inline bool operator > (const field_element& gfe)
{
return (poly_value_ > gfe.poly_value_);
}
inline bool operator > (const field_symbol& v)
{
return (poly_value_ > v);
}
inline field_symbol index() const
{
return field_.index(poly_value_);
}
inline field_symbol poly() const
{
return poly_value_;
}
inline field_symbol& poly()
{
return poly_value_;
}
inline const field& galois_field() const
{
return field_;
}
inline field_symbol inverse() const
{
return field_.inverse(poly_value_);
}
inline void normalize()
{
poly_value_ &= field_.size();
}
friend std::ostream& operator << (std::ostream& os, const field_element& gfe);
private:
const field& field_;
field_symbol poly_value_;
};
inline field_element operator + (const field_element& a, const field_element& b);
inline field_element operator - (const field_element& a, const field_element& b);
inline field_element operator * (const field_element& a, const field_element& b);
inline field_element operator * (const field_element& a, const field_symbol& b);
inline field_element operator * (const field_symbol& a, const field_element& b);
inline field_element operator / (const field_element& a, const field_element& b);
inline field_element operator ^ (const field_element& a, const int& b);
inline std::ostream& operator << (std::ostream& os, const field_element& gfe)
{
os << gfe.poly_value_;
return os;
}
inline field_element operator + (const field_element& a, const field_element& b)
{
field_element result = a;
result += b;
return result;
}
inline field_element operator - (const field_element& a, const field_element& b)
{
field_element result = a;
result -= b;
return result;
}
inline field_element operator * (const field_element& a, const field_element& b)
{
field_element result = a;
result *= b;
return result;
}
inline field_element operator * (const field_element& a, const field_symbol& b)
{
field_element result = a;
result *= b;
return result;
}
inline field_element operator * (const field_symbol& a, const field_element& b)
{
field_element result = b;
result *= a;
return result;
}
inline field_element operator / (const field_element& a, const field_element& b)
{
field_element result = a;
result /= b;
return result;
}
inline field_element operator ^ (const field_element& a, const int& b)
{
field_element result = a;
result ^= b;
return result;
}
} // namespace galois
} // namespace schifra
#endif

View File

@ -0,0 +1,839 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
#define INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
#include <cassert>
#include <iostream>
#include <vector>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
namespace schifra
{
namespace galois
{
class field_polynomial
{
public:
field_polynomial(const field& gfield);
field_polynomial(const field& gfield, const unsigned int& degree);
field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[]);
field_polynomial(const field_polynomial& polynomial);
field_polynomial(const field_element& gfe);
~field_polynomial() {}
bool valid() const;
int deg() const;
const field& galois_field() const;
void set_degree(const unsigned int& x);
void simplify();
field_polynomial& operator = (const field_polynomial& polynomial);
field_polynomial& operator = (const field_element& element);
field_polynomial& operator += (const field_polynomial& element);
field_polynomial& operator += (const field_element& element);
field_polynomial& operator -= (const field_polynomial& element);
field_polynomial& operator -= (const field_element& element);
field_polynomial& operator *= (const field_polynomial& polynomial);
field_polynomial& operator *= (const field_element& element);
field_polynomial& operator /= (const field_polynomial& divisor);
field_polynomial& operator /= (const field_element& element);
field_polynomial& operator %= (const field_polynomial& divisor);
field_polynomial& operator %= (const unsigned int& power);
field_polynomial& operator ^= (const unsigned int& n);
field_polynomial& operator <<= (const unsigned int& n);
field_polynomial& operator >>= (const unsigned int& n);
field_element& operator[] (const std::size_t& term);
field_element operator() (const field_element& value);
field_element operator() (field_symbol value);
const field_element& operator[](const std::size_t& term) const;
const field_element operator()(const field_element& value) const;
const field_element operator()(field_symbol value) const;
bool operator==(const field_polynomial& polynomial) const;
bool operator!=(const field_polynomial& polynomial) const;
bool monic() const;
field_polynomial derivative() const;
friend std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial);
private:
typedef std::vector<field_element>::iterator poly_iter;
typedef std::vector<field_element>::const_iterator const_poly_iter;
void simplify(field_polynomial& polynomial) const;
field& field_;
std::vector<field_element> poly_;
};
field_polynomial operator + (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator + (const field_polynomial& a, const field_element& b);
field_polynomial operator + (const field_element& a, const field_polynomial& b);
field_polynomial operator + (const field_polynomial& a, const field_symbol& b);
field_polynomial operator + (const field_symbol& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_element& b);
field_polynomial operator - (const field_element& a, const field_polynomial& b);
field_polynomial operator - (const field_polynomial& a, const field_symbol& b);
field_polynomial operator - (const field_symbol& a, const field_polynomial& b);
field_polynomial operator * (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator * (const field_element& a, const field_polynomial& b);
field_polynomial operator * (const field_polynomial& a, const field_element& b);
field_polynomial operator / (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator / (const field_polynomial& a, const field_element& b);
field_polynomial operator % (const field_polynomial& a, const field_polynomial& b);
field_polynomial operator % (const field_polynomial& a, const unsigned int& power);
field_polynomial operator ^ (const field_polynomial& a, const int& n);
field_polynomial operator <<(const field_polynomial& a, const unsigned int& n);
field_polynomial operator >>(const field_polynomial& a, const unsigned int& n);
field_polynomial gcd(const field_polynomial& a, const field_polynomial& b);
inline field_polynomial::field_polynomial(const field& gfield)
: field_(const_cast<field&>(gfield))
{
poly_.clear();
poly_.reserve(256);
}
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree)
: field_(const_cast<field&>(gfield))
{
poly_.reserve(256);
poly_.resize(degree + 1,field_element(field_,0));
}
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[])
: field_(const_cast<field&>(gfield))
{
poly_.reserve(256);
if (element != NULL)
{
/*
It is assumed that element is an array of field elements
with size/element count of degree + 1.
*/
for (unsigned int i = 0; i <= degree; ++i)
{
poly_.push_back(element[i]);
}
}
else
poly_.resize(degree + 1, field_element(field_, 0));
}
inline field_polynomial::field_polynomial(const field_polynomial& polynomial)
: field_(const_cast<field&>(polynomial.field_)),
poly_ (polynomial.poly_)
{}
inline field_polynomial::field_polynomial(const field_element& element)
: field_(const_cast<field&>(element.galois_field()))
{
poly_.resize(1,element);
}
inline bool field_polynomial::valid() const
{
return (poly_.size() > 0);
}
inline int field_polynomial::deg() const
{
return static_cast<int>(poly_.size()) - 1;
}
inline const field& field_polynomial::galois_field() const
{
return field_;
}
inline void field_polynomial::set_degree(const unsigned int& x)
{
poly_.resize(x - 1,field_element(field_,0));
}
inline field_polynomial& field_polynomial::operator = (const field_polynomial& polynomial)
{
if ((this != &polynomial) && (&field_ == &(polynomial.field_)))
{
poly_ = polynomial.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator = (const field_element& element)
{
if (&field_ == &(element.galois_field()))
{
poly_.resize(1,element);
}
return *this;
}
inline field_polynomial& field_polynomial::operator += (const field_polynomial& polynomial)
{
if (&field_ == &(polynomial.field_))
{
if (poly_.size() < polynomial.poly_.size())
{
const_poly_iter it0 = polynomial.poly_.begin();
for (poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
{
(*it1) += (*it0);
}
while (it0 != polynomial.poly_.end())
{
poly_.push_back(*it0);
++it0;
}
}
else
{
poly_iter it0 = poly_.begin();
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it0, ++it1)
{
(*it0) += (*it1);
}
}
simplify(*this);
}
return *this;
}
inline field_polynomial& field_polynomial::operator += (const field_element& element)
{
poly_[0] += element;
return *this;
}
inline field_polynomial& field_polynomial::operator -= (const field_polynomial& element)
{
return (*this += element);
}
inline field_polynomial& field_polynomial::operator -= (const field_element& element)
{
poly_[0] -= element;
return *this;
}
inline field_polynomial& field_polynomial::operator *= (const field_polynomial& polynomial)
{
if (&field_ == &(polynomial.field_))
{
field_polynomial product(field_,deg() + polynomial.deg() + 1);
poly_iter result_it = product.poly_.begin();
for (poly_iter it0 = poly_.begin(); it0 != poly_.end(); ++it0)
{
poly_iter current_result_it = result_it;
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it1)
{
(*current_result_it) += (*it0) * (*it1);
++current_result_it;
}
++result_it;
}
simplify(product);
poly_ = product.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator *= (const field_element& element)
{
if (field_ == element.galois_field())
{
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
{
(*it) *= element;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator /= (const field_polynomial& divisor)
{
if (
(&field_ == &divisor.field_) &&
(deg() >= divisor.deg()) &&
(divisor.deg() >= 0)
)
{
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
field_polynomial remainder(field_, divisor.deg() - 1);
for (int i = static_cast<int>(deg()); i >= 0; i--)
{
if (i <= static_cast<int>(quotient.deg()))
{
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
}
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
}
else
{
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1];
}
remainder[0] = poly_[i];
}
}
simplify(quotient);
poly_ = quotient.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator /= (const field_element& element)
{
if (field_ == element.galois_field())
{
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
{
(*it) /= element;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator %= (const field_polynomial& divisor)
{
if (
(field_ == divisor.field_) &&
(deg() >= divisor.deg() ) &&
(divisor.deg() >= 0 )
)
{
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
field_polynomial remainder(field_, divisor.deg() - 1);
for (int i = static_cast<int>(deg()); i >= 0; i--)
{
if (i <= static_cast<int>(quotient.deg()))
{
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
}
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
}
else
{
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
{
remainder[j] = remainder[j - 1];
}
remainder[0] = poly_[i];
}
}
poly_ = remainder.poly_;
}
return *this;
}
inline field_polynomial& field_polynomial::operator %= (const unsigned int& power)
{
if (poly_.size() >= power)
{
poly_.resize(power,field_element(field_,0));
simplify(*this);
}
return *this;
}
inline field_polynomial& field_polynomial::operator ^= (const unsigned int& n)
{
field_polynomial result = *this;
for (std::size_t i = 0; i < n; ++i)
{
result *= *this;
}
*this = result;
return *this;
}
inline field_polynomial& field_polynomial::operator <<= (const unsigned int& n)
{
if (poly_.size() > 0)
{
size_t initial_size = poly_.size();
poly_.resize(poly_.size() + n, field_element(field_,0));
for (size_t i = initial_size - 1; static_cast<int>(i) >= 0; --i)
{
poly_[i + n] = poly_[i];
}
for (unsigned int i = 0; i < n; ++i)
{
poly_[i] = 0;
}
}
return *this;
}
inline field_polynomial& field_polynomial::operator >>= (const unsigned int& n)
{
if (n <= poly_.size())
{
for (unsigned int i = 0; i <= deg() - n; ++i)
{
poly_[i] = poly_[i + n];
}
poly_.resize(poly_.size() - n,field_element(field_,0));
}
else if (static_cast<int>(n) >= (deg() + 1))
{
poly_.resize(0,field_element(field_,0));
}
return *this;
}
inline const field_element& field_polynomial::operator [] (const std::size_t& term) const
{
assert(term < poly_.size());
return poly_[term];
}
inline field_element& field_polynomial::operator [] (const std::size_t& term)
{
assert(term < poly_.size());
return poly_[term];
}
inline field_element field_polynomial::operator () (const field_element& value)
{
field_element result(field_,0);
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
field_symbol value_poly_form = value.poly();
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
}
result = total_sum;
}
return result;
}
inline const field_element field_polynomial::operator () (const field_element& value) const
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
field_symbol value_poly_form = value.poly();
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline field_element field_polynomial::operator () (field_symbol value)
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value,i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline const field_element field_polynomial::operator () (field_symbol value) const
{
if (!poly_.empty())
{
int i = 0;
field_symbol total_sum = 0 ;
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
{
total_sum ^= field_.mul(field_.exp(value, i), (*it).poly());
}
return field_element(field_,total_sum);
}
return field_element(field_,0);
}
inline bool field_polynomial::operator == (const field_polynomial& polynomial) const
{
if (field_ == polynomial.field_)
{
if (poly_.size() != polynomial.poly_.size())
return false;
else
{
const_poly_iter it0 = polynomial.poly_.begin();
for (const_poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
{
if ((*it0) != (*it1))
return false;
}
return true;
}
}
else
return false;
}
inline bool field_polynomial::operator != (const field_polynomial& polynomial) const
{
return !(*this == polynomial);
}
inline field_polynomial field_polynomial::derivative() const
{
if ((*this).poly_.size() > 1)
{
field_polynomial deriv(field_,deg());
const std::size_t upper_bound = poly_.size() - 1;
for (std::size_t i = 0; i < upper_bound; i += 2)
{
deriv.poly_[i] = poly_[i + 1];
}
simplify(deriv);
return deriv;
}
return field_polynomial(field_,0);
}
inline bool field_polynomial::monic() const
{
return (poly_[poly_.size() - 1] == static_cast<galois::field_symbol>(1));
}
inline void field_polynomial::simplify()
{
simplify(*this);
}
inline void field_polynomial::simplify(field_polynomial& polynomial) const
{
std::size_t poly_size = polynomial.poly_.size();
if ((poly_size > 0) && (polynomial.poly_.back() == 0))
{
poly_iter it = polynomial.poly_.end ();
poly_iter begin = polynomial.poly_.begin();
std::size_t count = 0;
while ((begin != it) && (*(--it) == 0))
{
++count;
}
if (0 != count)
{
polynomial.poly_.resize(poly_size - count, field_element(field_,0));
}
}
}
inline field_polynomial operator + (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result += b;
return result;
}
inline field_polynomial operator + (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result += b;
return result;
}
inline field_polynomial operator + (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result += a;
return result;
}
inline field_polynomial operator + (const field_polynomial& a, const field_symbol& b)
{
return a + field_element(a.galois_field(),b);
}
inline field_polynomial operator + (const field_symbol& a, const field_polynomial& b)
{
return b + field_element(b.galois_field(),a);
}
inline field_polynomial operator - (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result -= b;
return result;
}
inline field_polynomial operator - (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result -= b;
return result;
}
inline field_polynomial operator - (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result -= a;
return result;
}
inline field_polynomial operator - (const field_polynomial& a, const field_symbol& b)
{
return a - field_element(a.galois_field(),b);
}
inline field_polynomial operator - (const field_symbol& a, const field_polynomial& b)
{
return b - field_element(b.galois_field(),a);
}
inline field_polynomial operator * (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result *= b;
return result;
}
inline field_polynomial operator * (const field_element& a, const field_polynomial& b)
{
field_polynomial result = b;
result *= a;
return result;
}
inline field_polynomial operator * (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result *= b;
return result;
}
inline field_polynomial operator / (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result /= b;
return result;
}
inline field_polynomial operator / (const field_polynomial& a, const field_element& b)
{
field_polynomial result = a;
result /= b;
return result;
}
inline field_polynomial operator % (const field_polynomial& a, const field_polynomial& b)
{
field_polynomial result = a;
result %= b;
return result;
}
inline field_polynomial operator % (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result %= n;
return result;
}
inline field_polynomial operator ^ (const field_polynomial& a, const int& n)
{
field_polynomial result = a;
result ^= n;
return result;
}
inline field_polynomial operator << (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result <<= n;
return result;
}
inline field_polynomial operator >> (const field_polynomial& a, const unsigned int& n)
{
field_polynomial result = a;
result >>= n;
return result;
}
inline field_polynomial gcd(const field_polynomial& a, const field_polynomial& b)
{
if (&a.galois_field() == &b.galois_field())
{
if ((!a.valid()) && (!b.valid()))
{
field_polynomial error_polynomial(a.galois_field());
return error_polynomial;
}
if (!a.valid()) return b;
if (!b.valid()) return a;
field_polynomial x = a % b;
field_polynomial y = b;
field_polynomial z = x;
while ((z = (y % x)).valid())
{
y = x;
x = z;
}
return x;
}
else
{
field_polynomial error_polynomial(a.galois_field());
return error_polynomial;
}
}
inline field_polynomial generate_X(const field& gfield)
{
const field_element xgfe[2] = {
galois::field_element(gfield, 0),
galois::field_element(gfield, 1)
};
field_polynomial X_(gfield,1,xgfe);
return X_;
}
inline std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial)
{
if (polynomial.deg() >= 0)
{
/*
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
{
os << polynomial.poly[i].index()
<< ((i != (polynomial.deg())) ? " " : "");
}
std::cout << " poly form: ";
*/
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
{
os << polynomial.poly_[i].poly()
<< " "
<< "x^"
<< i
<< ((static_cast<int>(i) != (polynomial.deg())) ? " + " : "");
}
}
return os;
}
} // namespace galois
} // namespace schifra
#endif

View File

@ -0,0 +1,115 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
#define INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <string>
#include <sstream>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
namespace schifra
{
namespace galois
{
inline std::string convert_to_string(const unsigned int& value, const unsigned int& width)
{
std::stringstream stream;
stream << std::setw(width) << std::setfill('0') << value;
return stream.str();
}
inline std::string convert_to_string(const int& value, const unsigned int& width)
{
std::stringstream stream;
stream << std::setw(width) << std::setfill('0') << value;
return stream.str();
}
inline std::string convert_to_bin(const unsigned int& value, const unsigned int& field_descriptor)
{
std::string output = std::string(field_descriptor, ' ');
for (unsigned int i = 0; i < field_descriptor; ++i)
{
output[i] = ((((value >> (field_descriptor - 1 - i)) & 1) == 1) ? '1' : '0');
}
return output;
}
inline void alpha_table(std::ostream& os, const field& gf)
{
std::vector<std::string> str_list;
for (unsigned int i = 0; i < gf.size() + 1; ++i)
{
str_list.push_back("alpha^" + convert_to_string(gf.index(i),2) + "\t" +
convert_to_bin (i,gf.pwr()) + "\t" +
convert_to_string(gf.alpha(i),2));
}
std::sort(str_list.begin(),str_list.end());
std::copy(str_list.begin(),str_list.end(),std::ostream_iterator<std::string>(os,"\n"));
}
inline void polynomial_alpha_form(std::ostream& os, const field_polynomial& polynomial)
{
for (int i = 0; i < (polynomial.deg() + 1); ++i)
{
field_symbol alpha_power = polynomial.galois_field().index(polynomial[i].poly());
if (alpha_power != 0)
os << static_cast<unsigned char>(224) << "^" << convert_to_string(alpha_power,2);
else
os << 1;
os << " * "
<< "x^"
<< i
<< ((i != (polynomial.deg())) ? " + " : "");
}
}
inline void polynomial_alpha_form(std::ostream& os, const std::string& prepend, const field_polynomial& polynomial)
{
os << prepend;
polynomial_alpha_form(os,polynomial);
os << std::endl;
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,201 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
#include <iostream>
namespace schifra
{
namespace reed_solomon
{
namespace bitio
{
template <std::size_t symbol_bit_count> class convert_data_to_symbol;
template <>
class convert_data_to_symbol<2>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=4)
{
(* s_it ) = (*d_it) & 0x03;
(*(s_it + 1)) = ((*d_it) >> 2) & 0x03;
(*(s_it + 2)) = ((*d_it) >> 4) & 0x03;
(*(s_it + 3)) = ((*d_it) >> 6) & 0x03;
}
}
};
template <>
class convert_data_to_symbol<4>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=2)
{
(* s_it ) = (*d_it) & 0x0F;
(*(s_it + 1)) = ((*d_it) >> 4) & 0x0F;
}
}
};
template <>
class convert_data_to_symbol<8>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*s_it) = (*d_it) & 0xFF;
}
}
};
template <>
class convert_data_to_symbol<16>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
const BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; i+=2, d_it+=2, ++s_it)
{
(*s_it) = (*d_it) & 0x000000FF;
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
}
}
};
template <>
class convert_data_to_symbol<24>
{
public:
template <typename BitBlock>
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
{
BitBlock* d_it = & data[0];
int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; i+=3, d_it+=3, ++s_it)
{
(*s_it) |= (*d_it) & 0x000000FF;
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
(*s_it) |= (static_cast<int>((*(d_it + 2))) << 16) & 0x00FF0000;
}
}
};
template <std::size_t symbol_bit_count> class convert_symbol_to_data;
template <>
class convert_symbol_to_data<4>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = (*s_it) & 0x0000000F;
(*d_it) |= ((*(s_it + 1)) & 0x0000000F) << 4;
}
}
};
template <>
class convert_symbol_to_data<8>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = static_cast<BitBlock>((*s_it) & 0xFF);
}
}
};
template <>
class convert_symbol_to_data<16>
{
public:
template <typename BitBlock>
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
{
BitBlock* d_it = & data[0];
const int* s_it = &symbol[0];
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
{
(*d_it) = (*s_it) & 0xFFFF;
}
}
};
} // namespace bitio
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,382 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
struct block
{
public:
typedef galois::field_symbol symbol_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef traits::symbol<code_length> symbol;
typedef block<code_length,fec_length,data_length> block_t;
enum error_t
{
e_no_error = 0,
e_encoder_error0 = 1,
e_encoder_error1 = 2,
e_decoder_error0 = 3,
e_decoder_error1 = 4,
e_decoder_error2 = 5,
e_decoder_error3 = 6,
e_decoder_error4 = 7
};
block()
: errors_detected (0),
errors_corrected(0),
zero_numerators (0),
unrecoverable(false),
error(e_no_error)
{
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
}
block(const std::string& _data, const std::string& _fec)
: errors_detected (0),
errors_corrected(0),
zero_numerators (0),
unrecoverable(false),
error(e_no_error)
{
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
for (std::size_t i = 0; i < data_length; ++i)
{
data[i] = static_cast<galois::field_symbol>(_data[i]);
}
for (std::size_t i = 0; i < fec_length; ++i)
{
data[i + data_length] = static_cast<galois::field_symbol>(_fec[i]);
}
}
galois::field_symbol& operator[](const std::size_t& index)
{
return data[index];
}
const galois::field_symbol& operator[](const std::size_t& index) const
{
return data[index];
}
galois::field_symbol& operator()(const std::size_t& index)
{
return operator[](index);
}
galois::field_symbol& fec(const std::size_t& index)
{
return data[data_length + index];
}
bool data_to_string(std::string& data_str) const
{
if (data_str.length() != data_length)
{
return false;
}
for (std::size_t i = 0; i < data_length; ++i)
{
data_str[i] = static_cast<char>(data[i]);
}
return true;
}
bool fec_to_string(std::string& fec_str) const
{
if (fec_str.length() != fec_length)
{
return false;
}
for (std::size_t i = 0; i < fec_length; ++i)
{
fec_str[i] = static_cast<char>(data[data_length + i]);
}
return true;
}
std::string fec_to_string() const
{
std::string fec_str(fec_length,0x00);
fec_to_string(fec_str);
return fec_str;
}
void clear(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < code_length; ++i)
{
data[i] = value;
}
}
void clear_data(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < data_length; ++i)
{
data[i] = value;
}
}
void clear_fec(galois::field_symbol value = 0)
{
for (std::size_t i = 0; i < fec_length; ++i)
{
data[data_length + i] = value;
}
}
void reset(galois::field_symbol value = 0)
{
clear(value);
errors_detected = 0;
errors_corrected = 0;
zero_numerators = 0;
unrecoverable = false;
error = e_no_error;
}
template <typename BlockType>
void copy_state(const BlockType& b)
{
errors_detected = b.errors_detected;
errors_corrected = b.errors_corrected;
zero_numerators = b.zero_numerators;
unrecoverable = b.unrecoverable;
error = static_cast<error_t>(b.error);
}
inline std::string error_as_string() const
{
switch (error)
{
case e_no_error : return "No Error";
case e_encoder_error0 : return "Invalid Encoder";
case e_encoder_error1 : return "Incompatible Generator Polynomial";
case e_decoder_error0 : return "Invalid Decoder";
case e_decoder_error1 : return "Decoder Failure - Non-zero Syndrome";
case e_decoder_error2 : return "Decoder Failure - Too Many Errors/Erasures";
case e_decoder_error3 : return "Decoder Failure - Invalid Symbol Correction";
case e_decoder_error4 : return "Decoder Failure - Invalid Codeword Correction";
default : return "Invalid Error Code";
}
}
std::size_t errors_detected;
std::size_t errors_corrected;
std::size_t zero_numerators;
bool unrecoverable;
error_t error;
galois::field_symbol data[code_length];
};
template <std::size_t code_length, std::size_t fec_length>
inline void copy(const block<code_length,fec_length>& src_block, block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < code_length; ++index)
{
dest_block.data[index] = src_block.data[index];
}
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void copy(const T src_data[], block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < (code_length - fec_length); ++index, ++src_data)
{
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void copy(const T src_data[],
const std::size_t& src_length,
block<code_length,fec_length>& dest_block)
{
for (std::size_t index = 0; index < src_length; ++index, ++src_data)
{
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
}
}
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
block<code_length,fec_length> dest_block_stack[stack_size])
{
for (std::size_t row = 0; row < stack_size; ++row)
{
copy(src_block_stack[row], dest_block_stack[row]);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline bool copy(const T src_data[],
const std::size_t src_length,
block<code_length,fec_length> dest_block_stack[stack_size])
{
const std::size_t data_length = code_length - fec_length;
if (src_length > (stack_size * data_length))
{
return false;
}
const std::size_t row_count = src_length / data_length;
for (std::size_t row = 0; row < row_count; ++row, src_data += data_length)
{
copy(src_data, dest_block_stack[row]);
}
if ((src_length % data_length) != 0)
{
copy(src_data, src_length % data_length, dest_block_stack[row_count]);
}
return true;
}
template <typename T, std::size_t code_length, std::size_t fec_length>
inline void full_copy(const block<code_length,fec_length>& src_block,
T dest_data[])
{
for (std::size_t i = 0; i < code_length; ++i, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block[i]);
}
}
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
T dest_data[])
{
const std::size_t data_length = code_length - fec_length;
for (std::size_t i = 0; i < stack_size; ++i)
{
for (std::size_t j = 0; j < data_length; ++j, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block_stack[i][j]);
}
}
}
template <std::size_t code_length, std::size_t fec_length>
inline std::ostream& operator<<(std::ostream& os, const block<code_length,fec_length>& rs_block)
{
for (std::size_t i = 0; i < code_length; ++i)
{
os << static_cast<char>(rs_block[i]);
}
return os;
}
template <typename T, std::size_t block_length>
struct data_block
{
public:
typedef T value_type;
T& operator[](const std::size_t index) { return data[index]; }
const T& operator[](const std::size_t index) const { return data[index]; }
T* begin() { return data; }
const T* begin() const { return data; }
T* end() { return data + block_length; }
const T* end() const { return data + block_length; }
void clear(T value = 0)
{
for (std::size_t i = 0; i < block_length; ++i)
{
data[i] = value;
}
}
private:
T data[block_length];
};
template <typename T, std::size_t block_length>
inline void copy(const data_block<T,block_length>& src_block, data_block<T,block_length>& dest_block)
{
for (std::size_t index = 0; index < block_length; ++index)
{
dest_block[index] = src_block[index];
}
}
template <typename T, std::size_t block_length, std::size_t stack_size>
inline void copy(const data_block<T,block_length> src_block_stack[stack_size],
data_block<T,block_length> dest_block_stack[stack_size])
{
for (std::size_t row = 0; row < stack_size; ++row)
{
copy(src_block_stack[row], dest_block_stack[row]);
}
}
template <typename T, std::size_t block_length>
inline void full_copy(const data_block<T,block_length>& src_block, T dest_data[])
{
for (std::size_t i = 0; i < block_length; ++i, ++dest_data)
{
(*dest_data) = static_cast<T>(src_block[i]);
}
}
typedef std::vector<std::size_t> erasure_locations_t;
} // namespace reed_solomon
} // namepsace schifra
#endif

View File

@ -0,0 +1,998 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
#include <cstddef>
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_ecc_traits.hpp"
#include "schifra_error_processes.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length,
std::size_t fec_length,
typename encoder_type = encoder<code_length,fec_length>,
typename decoder_type = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
class codec_validator
{
public:
typedef block<code_length,fec_length> block_type;
codec_validator(const galois::field& gf,
const unsigned int gpii,
const std::string& msg)
: field_(gf),
generator_polynomial_(galois::field_polynomial(field_)),
rs_encoder_(reinterpret_cast<encoder_type*>(0)),
rs_decoder_(reinterpret_cast<decoder_type*>(0)),
message(msg),
genpoly_initial_index_(gpii),
blocks_processed_(0),
block_failures_(0)
{
traits::equivalent_encoder_decoder<encoder_type,decoder_type>();
if (
!make_sequential_root_generator_polynomial(field_,
genpoly_initial_index_,
fec_length,
generator_polynomial_)
)
{
return;
}
rs_encoder_ = new encoder_type(field_,generator_polynomial_);
rs_decoder_ = new decoder_type(field_,genpoly_initial_index_);
if (!rs_encoder_->encode(message,rs_block_original))
{
std::cout << "codec_validator() - ERROR: Encoding process failed!" << std::endl;
return;
}
}
bool execute()
{
schifra::utils::timer timer;
timer.start();
bool result = stage1() &&
stage2() &&
stage3() &&
stage4() &&
stage5() &&
stage6() &&
stage7() &&
stage8() &&
stage9() &&
stage10() &&
stage11() &&
stage12() ;
timer.stop();
double time = timer.time();
print_codec_properties();
std::cout << "Blocks decoded: " << blocks_processed_ <<
"\tDecoding Failures: " << block_failures_ <<
"\tRate: " << ((blocks_processed_ * data_length) * 8.0) / (1048576.0 * time) << "Mbps" << std::endl;
/*
Note: The throughput rate is not only the throughput of reed solomon
encoding and decoding, but also that of the steps needed to add
simulated transmission errors to the reed solomon block such as
the calculation of the positions and additions of errors and
erasures to the reed solomon block, which normally in a true
data transmission medium would not be taken into consideration.
*/
return result;
}
~codec_validator()
{
delete rs_encoder_;
delete rs_decoder_;
}
void print_codec_properties()
{
std::cout << "Codec: RS(" << code_length << "," << data_length << "," << fec_length <<") ";
}
private:
bool stage1()
{
/* Burst Error Only Combinations */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors
(
rs_block,
error_count,
start_position,
1
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage1() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage1() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage1() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage1() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage1() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
bool stage2()
{
/* Burst Erasure Only Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_all_erasures
(
rs_block,
erasure_list,
erasure_count,
start_position,
1
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage2() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
std::cout << "stage2() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage2() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != erasure_count)
{
print_codec_properties();
std::cout << "stage2() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != erasure_count)
{
print_codec_properties();
std::cout << "stage2() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage3()
{
/* Consecutive Burst Erasure and Error Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::erasures_errors,
start_position,erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage3() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage3() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage3() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage4()
{
/* Consecutive Burst Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::errors_erasures,
start_position,
erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage4() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage4() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage4() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage5()
{
/* Distanced Burst Erasure and Error Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::erasures_errors,
start_position,
erasure_count,
erasure_list,
between_distance
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage5() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage5() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage5() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage6()
{
/* Distanced Burst Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_errors_erasures
(
rs_block,
error_mode::errors_erasures,
start_position,
erasure_count,
erasure_list,between_distance
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage6() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage6() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage6() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage7()
{
/* Intermittent Error Combinations */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t error_count = 1; error_count < (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t scale = 1; scale < 5; ++scale)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors
(
rs_block,
error_count,
start_position,
scale
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage7() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage7() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage7() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage7() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage7() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage8()
{
/* Intermittent Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t scale = 4; scale < 5; ++scale)
{
block_type rs_block = rs_block_original;
corrupt_message_all_erasures
(
rs_block,
erasure_list,
erasure_count,
start_position,
scale
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage8() - Decoding Failure! start position: " << start_position << "\t scale: " << scale << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage8() - Error Correcting Failure! start position: " << start_position << "\t scale: " << scale <<std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != (rs_block.errors_corrected + rs_block.zero_numerators))
{
print_codec_properties();
std::cout << "stage8() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected > erasure_count)
{
print_codec_properties();
std::cout << "stage8() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected > erasure_count)
{
print_codec_properties();
std::cout << "stage8() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
}
return (block_failures_ == initial_failure_count);
}
bool stage9()
{
/* Burst Interleaved Error and Erasure Combinations */
const std::size_t initial_failure_count = block_failures_;
erasure_locations_t erasure_list;
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block_type rs_block = rs_block_original;
corrupt_message_interleaved_errors_erasures
(
rs_block,
start_position,
erasure_count,
erasure_list
);
if (!rs_decoder_->decode(rs_block,erasure_list))
{
print_codec_properties();
std::cout << "stage9() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage9() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage9() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
erasure_list.clear();
}
}
return (block_failures_ == initial_failure_count);
}
bool stage10()
{
/* Segmented Burst Errors */
const std::size_t initial_failure_count = block_failures_;
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
for (std::size_t distance_between_blocks = 0; distance_between_blocks < 5; ++distance_between_blocks)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors_segmented
(
rs_block,
start_position,
distance_between_blocks
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage10() - Decoding Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage10() - Error Correcting Failure! start position: " << start_position << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage10() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
bool stage11()
{
/* No Errors */
const std::size_t initial_failure_count = block_failures_;
block_type rs_block = rs_block_original;
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage11() - Decoding Failure!" << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != 0)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != 0)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
else if (rs_block.unrecoverable)
{
print_codec_properties();
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
++block_failures_;
}
++blocks_processed_;
return (block_failures_ == initial_failure_count);
}
bool stage12()
{
/* Random Errors Only */
const std::size_t initial_failure_count = block_failures_;
std::vector<std::size_t> random_error_index;
generate_error_index((fec_length >> 1),random_error_index,0xA5A5A5A5);
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t error_index = 0; error_index < error_index_size; ++error_index)
{
block_type rs_block = rs_block_original;
corrupt_message_all_errors_at_index
(
rs_block,
error_count,
error_index,
random_error_index
);
if (!rs_decoder_->decode(rs_block))
{
print_codec_properties();
std::cout << "stage12() - Decoding Failure! error index: " << error_index << std::endl;
++block_failures_;
}
else if (!is_block_equivelent(rs_block,message))
{
print_codec_properties();
std::cout << "stage12() - Error Correcting Failure! error index: " << error_index << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != rs_block.errors_corrected)
{
print_codec_properties();
std::cout << "stage12() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
++block_failures_;
}
else if (rs_block.errors_detected != error_count)
{
print_codec_properties();
std::cout << "stage12() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
++block_failures_;
}
else if (rs_block.errors_corrected != error_count)
{
print_codec_properties();
std::cout << "stage12() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
++block_failures_;
}
++blocks_processed_;
}
}
return (block_failures_ == initial_failure_count);
}
protected:
codec_validator() {}
private:
codec_validator(const codec_validator&);
const codec_validator& operator=(const codec_validator&);
const galois::field& field_;
galois::field_polynomial generator_polynomial_;
encoder_type* rs_encoder_;
decoder_type* rs_decoder_;
block_type rs_block_original;
const std::string& message;
const unsigned int genpoly_initial_index_;
unsigned int blocks_processed_;
unsigned int block_failures_;
};
template <std::size_t data_length>
void create_messages(std::vector<std::string>& message_list, const bool full_test_set = false)
{
/* Various message bit patterns */
message_list.clear();
if (full_test_set)
{
for (std::size_t i = 0; i < 256; ++i)
{
message_list.push_back(std::string(data_length, static_cast<unsigned char>(i)));
}
}
else
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
}
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0xFF);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0x00);
}
message_list.push_back(tmp_str);
}
template <std::size_t field_descriptor, std::size_t gen_poly_index, std::size_t code_length, std::size_t fec_length>
inline bool codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
{
const unsigned int data_length = code_length - fec_length;
galois::field field(field_descriptor,prim_poly_size,prim_poly);
std::vector<std::string> message_list;
create_messages<data_length>(message_list);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
codec_validator<code_length,fec_length>
validator(field, gen_poly_index, message_list[i]);
if (!validator.execute())
{
return false;
}
}
return true;
}
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length>
inline bool shortened_codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
{
typedef shortened_encoder<code_length,fec_length> encoder_type;
typedef shortened_decoder<code_length,fec_length> decoder_type;
const unsigned int data_length = code_length - fec_length;
galois::field field(field_descriptor,prim_poly_size,prim_poly);
std::vector<std::string> message_list;
create_messages<data_length>(message_list);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
codec_validator<code_length,fec_length,encoder_type,decoder_type>
validator(field,gen_poly_index,message_list[i]);
if (!validator.execute())
{
return false;
}
}
return true;
}
inline bool codec_validation_test00()
{
return codec_validation_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 22>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 24>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
codec_validation_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ;
}
inline bool codec_validation_test01()
{
return shortened_codec_validation_test<8,120,126,14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 1 RS Code */
shortened_codec_validation_test<8,120,194,16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 2 RS Code */
shortened_codec_validation_test<8,120,219,18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 3 RS Code */
shortened_codec_validation_test<8,120,225,20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 4 RS Code */
shortened_codec_validation_test<8, 1,204,16>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* DBV/MPEG-2 TSP RS Code */
shortened_codec_validation_test<8, 1,104,27>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Outer RS Code */
shortened_codec_validation_test<8, 1,204,12>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Inner RS Code */
shortened_codec_validation_test<8,120, 72,10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ; /* VDL Mode 3 RS Code */
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,485 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class decoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
decoder(const galois::field& field, const unsigned int& gen_initial_index = 0)
: decoder_valid_(field.size() == code_length),
field_(field),
X_(galois::generate_X(field_)),
gen_initial_index_(gen_initial_index)
{
if (decoder_valid_)
{
//Note: code_length and field size can be used interchangeably
create_lookup_tables();
}
};
const galois::field& field() const
{
return field_;
}
bool decode(block_type& rsblock) const
{
std::vector<std::size_t> erasure_list;
return decode(rsblock,erasure_list);
}
bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
{
if ((!decoder_valid_) || (erasure_list.size() > fec_length))
{
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error0;
return false;
}
galois::field_polynomial received(field_,code_length - 1);
load_message(received,rsblock);
galois::field_polynomial syndrome(field_);
if (compute_syndrome(received,syndrome) == 0)
{
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = false;
return true;
}
galois::field_polynomial lambda(galois::field_element(field_,1));
erasure_locations_t erasure_locations;
if (!erasure_list.empty())
{
prepare_erasure_list(erasure_locations, erasure_list);
compute_gamma(lambda, erasure_locations);
}
if (erasure_list.size() < fec_length)
{
modified_berlekamp_massey_algorithm(lambda, syndrome, erasure_list.size());
}
std::vector<int> error_locations;
find_roots(lambda, error_locations);
if (0 == error_locations.size())
{
/*
Syndrome is non-zero yet no error locations have
been obtained, conclusion:
It is possible that there are MORE errrors in the
message than can be detected and corrected for this
particular code.
*/
rsblock.errors_detected = 0;
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error1;
return false;
}
else if (((2 * error_locations.size()) - erasure_list.size()) > fec_length)
{
/*
Too many errors\erasures! 2E + S <= fec_length
L = E + S
E = L - S
2E = 2L - 2S
2E + S = 2L - 2S + S
= 2L - S
Where:
L : Error Locations
E : Errors
S : Erasures
*/
rsblock.errors_detected = error_locations.size();
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error2;
return false;
}
else
rsblock.errors_detected = error_locations.size();
return forney_algorithm(error_locations, lambda, syndrome, rsblock);
}
private:
decoder();
decoder(const decoder& dec);
decoder& operator=(const decoder& dec);
protected:
void load_message(galois::field_polynomial& received, const block_type& rsblock) const
{
/*
Load message data into received polynomial in reverse order.
*/
for (std::size_t i = 0; i < code_length; ++i)
{
received[code_length - 1 - i] = rsblock[i];
}
}
void create_lookup_tables()
{
root_exponent_table_.reserve(field_.size() + 1);
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
{
root_exponent_table_.push_back(field_.exp(field_.alpha(code_length - i),(1 - gen_initial_index_)));
}
syndrome_exponent_table_.reserve(fec_length);
for (int i = 0; i < static_cast<int>(fec_length); ++i)
{
syndrome_exponent_table_.push_back(field_.alpha(gen_initial_index_ + i));
}
gamma_table_.reserve(field_.size() + 1);
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
{
gamma_table_.push_back((1 + (X_ * galois::field_element(field_,field_.alpha(i)))));
}
}
void prepare_erasure_list(erasure_locations_t& erasure_locations, const erasure_locations_t& erasure_list) const
{
/*
Note: 1. Erasure positions must be unique.
2. Erasure positions must exist within the code block.
There are NO exceptions to these rules!
*/
erasure_locations.resize(erasure_list.size());
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
erasure_locations[i] = (code_length - 1 - erasure_list[i]);
}
}
int compute_syndrome(const galois::field_polynomial& received,
galois::field_polynomial& syndrome) const
{
int error_flag = 0;
syndrome = galois::field_polynomial(field_,fec_length - 1);
for (std::size_t i = 0; i < fec_length; ++i)
{
syndrome[i] = received(syndrome_exponent_table_[i]);
error_flag |= syndrome[i].poly();
}
return error_flag;
}
void compute_gamma(galois::field_polynomial& gamma, const erasure_locations_t& erasure_locations) const
{
for (std::size_t i = 0; i < erasure_locations.size(); ++i)
{
gamma *= gamma_table_[erasure_locations[i]];
}
}
void find_roots(const galois::field_polynomial& poly, std::vector<int>& root_list) const
{
/*
Chien Search: Find the roots of the error locator polynomial
via an exhaustive search over all non-zero elements in the
given finite field.
*/
root_list.reserve(fec_length << 1);
root_list.resize(0);
const std::size_t polynomial_degree = poly.deg();
for (int i = 1; i <= static_cast<int>(code_length); ++i)
{
if (0 == poly(field_.alpha(i)).poly())
{
root_list.push_back(i);
if (polynomial_degree == root_list.size())
{
break;
}
}
}
}
void compute_discrepancy(galois::field_element& discrepancy,
const galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
const std::size_t& l,
const std::size_t& round) const
{
/*
Compute the lambda discrepancy at the current round of BMA
*/
const std::size_t upper_bound = std::min(static_cast<int>(l), lambda.deg());
discrepancy = 0;
for (std::size_t i = 0; i <= upper_bound; ++i)
{
discrepancy += lambda[i] * syndrome[round - i];
}
}
void modified_berlekamp_massey_algorithm(galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
const std::size_t erasure_count) const
{
/*
Modified Berlekamp-Massey Algorithm
Identify the shortest length linear feed-back shift register (LFSR)
that will generate the sequence equivalent to the syndrome.
*/
int i = -1;
std::size_t l = erasure_count;
galois::field_element discrepancy(field_,0);
galois::field_polynomial previous_lambda = lambda << 1;
for (std::size_t round = erasure_count; round < fec_length; ++round)
{
compute_discrepancy(discrepancy, lambda, syndrome, l, round);
if (discrepancy != 0)
{
galois::field_polynomial tau = lambda - (discrepancy * previous_lambda);
if (static_cast<int>(l) < (static_cast<int>(round) - i))
{
const std::size_t tmp = round - i;
i = static_cast<int>(round - l);
l = tmp;
previous_lambda = lambda / discrepancy;
}
lambda = tau;
}
previous_lambda <<= 1;
}
}
bool forney_algorithm(const std::vector<int>& error_locations,
const galois::field_polynomial& lambda,
const galois::field_polynomial& syndrome,
block_type& rsblock) const
{
/*
The Forney algorithm for computing the error magnitudes
*/
const galois::field_polynomial omega = (lambda * syndrome) % fec_length;
const galois::field_polynomial lambda_derivative = lambda.derivative();
rsblock.errors_corrected = 0;
rsblock.zero_numerators = 0;
for (std::size_t i = 0; i < error_locations.size(); ++i)
{
const unsigned int error_location = error_locations[i];
const galois::field_symbol alpha_inverse = field_.alpha(error_location);
const galois::field_symbol numerator = (omega(alpha_inverse) * root_exponent_table_[error_location]).poly();
const galois::field_symbol denominator = lambda_derivative(alpha_inverse).poly();
if (0 != numerator)
{
if (0 != denominator)
{
rsblock[error_location - 1] ^= field_.div(numerator, denominator);
rsblock.errors_corrected++;
}
else
{
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error3;
return false;
}
}
else
++rsblock.zero_numerators;
}
if (lambda.deg() == static_cast<int>(rsblock.errors_detected))
return true;
else
{
rsblock.unrecoverable = true;
rsblock.error = block_type::e_decoder_error4;
return false;
}
}
protected:
bool decoder_valid_;
const galois::field& field_;
std::vector<galois::field_symbol> root_exponent_table_;
std::vector<galois::field_symbol> syndrome_exponent_table_;
std::vector<galois::field_polynomial> gamma_table_;
const galois::field_polynomial X_;
const unsigned int gen_initial_index_;
};
template <std::size_t code_length,
std::size_t fec_length,
std::size_t data_length = code_length - fec_length,
std::size_t natural_length = 255, // Needs to be in-sync with field size
std::size_t padding_length = natural_length - data_length - fec_length>
class shortened_decoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
shortened_decoder(const galois::field& field, const unsigned int gen_initial_index = 0)
: decoder_(field, gen_initial_index)
{}
inline bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
{
typename natural_decoder_type::block_type block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < code_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
erasure_locations_t shifted_position_erasure_list(erasure_list.size(),0);
for (std::size_t i = 0; i < erasure_list.size(); ++i)
{
shifted_position_erasure_list[i] = erasure_list[i] + padding_length;
}
if (decoder_.decode(block, shifted_position_erasure_list))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
rsblock.copy_state(block);
return true;
}
else
{
rsblock.copy_state(block);
return false;
}
}
inline bool decode(block_type& rsblock) const
{
typename natural_decoder_type::block_type block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < code_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
if (decoder_.decode(block))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
rsblock.copy_state(block);
return true;
}
else
{
rsblock.copy_state(block);
return false;
}
}
private:
typedef decoder<natural_length,fec_length> natural_decoder_type;
const natural_decoder_type decoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,204 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class encoder
{
public:
typedef traits::reed_solomon_triat<code_length, fec_length,data_length> trait;
typedef block<code_length, fec_length> block_type;
encoder(const galois::field& gfield, const galois::field_polynomial& generator)
: encoder_valid_(code_length == gfield.size()),
field_(gfield),
generator_(generator)
{}
~encoder()
{}
inline bool encode(block_type& rsblock) const
{
if (!encoder_valid_)
{
rsblock.error = block_type::e_encoder_error0;
return false;
}
const galois::field_polynomial parities = msg_poly(rsblock) % generator_;
const galois::field_symbol mask = field_.mask();
if (parities.deg() == (fec_length - 1))
{
for (std::size_t i = 0; i < fec_length; ++i)
{
rsblock.fec(i) = parities[fec_length - 1 - i].poly() & mask;
}
}
else
{
/*
Note: Encoder should never branch here.
Possible issues to look for:
1. Generator polynomial degree is not equivelent to fec length
2. Field and code length are not consistent.
*/
rsblock.error = block_type::e_encoder_error1;
return false;
}
return true;
}
inline bool encode(const std::string& data, block_type& rsblock) const
{
std::string::const_iterator itr = data.begin();
const galois::field_symbol mask = field_.mask();
for (std::size_t i = 0; i < data_length; ++i, ++itr)
{
rsblock.data[i] = static_cast<typename block_type::symbol_type>(*itr) & mask;
}
return encode(rsblock);
}
private:
encoder();
encoder(const encoder& enc);
encoder& operator=(const encoder& enc);
inline galois::field_polynomial msg_poly(const block_type& rsblock) const
{
galois::field_polynomial message(field_, code_length);
for (std::size_t i = fec_length; i < code_length; ++i)
{
message[i] = rsblock.data[code_length - 1 - i];
}
return message;
}
const bool encoder_valid_;
const galois::field& field_;
const galois::field_polynomial generator_;
};
template <std::size_t code_length,
std::size_t fec_length ,
std::size_t data_length = code_length - fec_length,
std::size_t natural_length = 255, // Needs to be in-sync with field size
std::size_t padding_length = natural_length - data_length - fec_length>
class shortened_encoder
{
public:
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef block<code_length,fec_length> block_type;
typedef block<natural_length,fec_length> short_block_t;
shortened_encoder(const galois::field& gfield,
const galois::field_polynomial& generator)
: encoder_(gfield, generator)
{}
inline bool encode(block_type& rsblock) const
{
short_block_t block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < data_length; ++i)
{
block.data[padding_length + i] = rsblock.data[i];
}
if (encoder_.encode(block))
{
for (std::size_t i = 0; i < fec_length; ++i)
{
rsblock.fec(i) = block.fec(i);
}
return true;
}
else
return false;
}
inline bool encode(const std::string& data, block_type& rsblock) const
{
short_block_t block;
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
for (std::size_t i = 0; i < data_length; ++i)
{
block.data[padding_length + i] = data[i];
}
if (encoder_.encode(block))
{
for (std::size_t i = 0; i < code_length; ++i)
{
rsblock.data[i] = block.data[padding_length + i];
}
return true;
}
else
return false;
}
private:
const encoder<natural_length,fec_length> encoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,171 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class file_decoder
{
public:
typedef decoder<code_length,fec_length> decoder_type;
typedef typename decoder_type::block_type block_type;
file_decoder(const decoder_type& decoder,
const std::string& input_file_name,
const std::string& output_file_name)
: current_block_index_(0)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (remaining_bytes == 0)
{
std::cout << "reed_solomon::file_decoder() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_decoder() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_decoder() - Error: output file could not be created." << std::endl;
return;
}
current_block_index_ = 0;
while (remaining_bytes >= code_length)
{
process_complete_block(decoder,in_stream,out_stream);
remaining_bytes -= code_length;
current_block_index_++;
}
if (remaining_bytes > 0)
{
process_partial_block(decoder,in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_complete_block(const decoder_type& decoder,
std::ifstream& in_stream,
std::ofstream& out_stream)
{
in_stream.read(&buffer_[0],static_cast<std::streamsize>(code_length));
copy<char,code_length,fec_length>(buffer_,code_length,block_);
if (!decoder.decode(block_))
{
std::cout << "reed_solomon::file_decoder.process_complete_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
for (std::size_t i = 0; i < data_length; ++i)
{
buffer_[i] = static_cast<char>(block_[i]);
}
out_stream.write(&buffer_[0],static_cast<std::streamsize>(data_length));
}
inline void process_partial_block(const decoder_type& decoder,
std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t& read_amount)
{
if (read_amount <= fec_length)
{
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
in_stream.read(&buffer_[0],static_cast<std::streamsize>(read_amount));
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
{
block_.data[i] = static_cast<typename block_type::symbol_type>(buffer_[i]);
}
if ((read_amount - fec_length) < data_length)
{
for (std::size_t i = (read_amount - fec_length); i < data_length; ++i)
{
block_.data[i] = 0;
}
}
for (std::size_t i = 0; i < fec_length; ++i)
{
block_.fec(i) = static_cast<typename block_type::symbol_type>(buffer_[(read_amount - fec_length) + i]);
}
if (!decoder.decode(block_))
{
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
return;
}
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
{
buffer_[i] = static_cast<char>(block_.data[i]);
}
out_stream.write(&buffer_[0],static_cast<std::streamsize>(read_amount - fec_length));
}
block_type block_;
std::size_t current_block_index_;
char buffer_[code_length];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,138 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
#include <cstring>
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class file_encoder
{
public:
typedef encoder<code_length,fec_length> encoder_type;
typedef typename encoder_type::block_type block_type;
file_encoder(const encoder_type& encoder,
const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (remaining_bytes == 0)
{
std::cout << "reed_solomon::file_encoder() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_encoder() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_encoder() - Error: output file could not be created." << std::endl;
return;
}
std::memset(data_buffer_,0,sizeof(data_buffer_));
std::memset(fec_buffer_ ,0,sizeof(fec_buffer_ ));
while (remaining_bytes >= data_length)
{
process_block(encoder,in_stream,out_stream,data_length);
remaining_bytes -= data_length;
}
if (remaining_bytes > 0)
{
process_block(encoder,in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(const encoder_type& encoder,
std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t& read_amount)
{
in_stream.read(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
for (std::size_t i = 0; i < read_amount; ++i)
{
block_.data[i] = (data_buffer_[i] & 0xFF);
}
if (read_amount < data_length)
{
for (std::size_t i = read_amount; i < data_length; ++i)
{
block_.data[i] = 0x00;
}
}
if (!encoder.encode(block_))
{
std::cout << "reed_solomon::file_encoder.process_block() - Error during encoding of block!" << std::endl;
return;
}
for (std::size_t i = 0; i < fec_length; ++i)
{
fec_buffer_[i] = static_cast<char>(block_.fec(i) & 0xFF);
}
out_stream.write(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
out_stream.write(&fec_buffer_[0],fec_length);
}
block_type block_;
char data_buffer_[data_length];
char fec_buffer_[fec_length];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,247 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
#include <iostream>
#include <string>
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_fileio.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t block_length, std::size_t stack_size>
class file_interleaver
{
public:
file_interleaver(const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
if (0 == remaining_bytes)
{
std::cout << "reed_solomon::file_interleaver() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_interleaver() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_interleaver() - Error: output file could not be created." << std::endl;
return;
}
while (remaining_bytes >= (block_length * stack_size))
{
process_block(in_stream,out_stream);
remaining_bytes -= (block_length * stack_size);
}
if (remaining_bytes > 0)
{
process_incomplete_block(in_stream,out_stream,remaining_bytes);
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(std::ifstream& in_stream,
std::ofstream& out_stream)
{
for (std::size_t i = 0; i < stack_size; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
interleave<char,block_length,stack_size>(block_stack_);
for (std::size_t i = 0; i < stack_size; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
}
inline void process_incomplete_block(std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t amount)
{
std::size_t complete_row_count = amount / block_length;
std::size_t remainder = amount % block_length;
for (std::size_t i = 0; i < complete_row_count; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
if (remainder == 0)
interleave<char,block_length,stack_size>(block_stack_,complete_row_count);
else
interleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
for (std::size_t i = 0; i < complete_row_count; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
}
data_block<char,block_length> block_stack_[stack_size];
};
template <std::size_t block_length, std::size_t stack_size>
class file_deinterleaver
{
public:
file_deinterleaver(const std::string& input_file_name,
const std::string& output_file_name)
{
std::size_t input_file_size = schifra::fileio::file_size(input_file_name);
if (input_file_size == 0)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: input file has ZERO size." << std::endl;
return;
}
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
if (!in_stream)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: input file could not be opened." << std::endl;
return;
}
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
if (!out_stream)
{
std::cout << "reed_solomon::file_deinterleaver() - Error: output file could not be created." << std::endl;
return;
}
for (std::size_t i = 0; i < (input_file_size / (block_length * stack_size)); ++i)
{
process_block(in_stream,out_stream);
}
if ((input_file_size % (block_length * stack_size)) != 0)
{
process_incomplete_block(in_stream,out_stream,(input_file_size % (block_length * stack_size)));
}
in_stream.close();
out_stream.close();
}
private:
inline void process_block(std::ifstream& in_stream,
std::ofstream& out_stream)
{
for (std::size_t i = 0; i < stack_size; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
deinterleave<char,block_length,stack_size>(block_stack_);
for (std::size_t i = 0; i < stack_size; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
}
inline void process_incomplete_block(std::ifstream& in_stream,
std::ofstream& out_stream,
const std::size_t amount)
{
std::size_t complete_row_count = amount / block_length;
std::size_t remainder = amount % block_length;
for (std::size_t i = 0; i < complete_row_count; ++i)
{
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
if (remainder == 0)
deinterleave<char,block_length>(block_stack_,complete_row_count);
else
deinterleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
for (std::size_t i = 0; i < complete_row_count; ++i)
{
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
}
if (remainder != 0)
{
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
}
}
data_block<char,block_length> block_stack_[stack_size];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,210 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
#define INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_polynomial.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
void* create_encoder(const galois::field& field,
const std::size_t& gen_poly_index)
{
const std::size_t data_length = code_length - fec_length;
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
galois::field_polynomial gen_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
gen_polynomial)
)
{
return reinterpret_cast<void*>(0);
}
return new encoder<code_length,fec_length>(field,gen_polynomial);
}
template <std::size_t code_length, std::size_t fec_length>
void* create_decoder(const galois::field& field,
const std::size_t& gen_poly_index)
{
const std::size_t data_length = code_length - fec_length;
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
return new decoder<code_length,fec_length>(field,static_cast<unsigned int>(gen_poly_index));
}
template <std::size_t code_length, std::size_t max_fec_length = 128>
class general_codec
{
public:
general_codec(const galois::field& field,
const std::size_t& gen_poly_index)
{
for (std::size_t i = 0; i < max_fec_length; ++i)
{
encoder_[i] = 0;
decoder_[i] = 0;
}
encoder_[ 2] = create_encoder<code_length, 2>(field, gen_poly_index);
encoder_[ 4] = create_encoder<code_length, 4>(field, gen_poly_index);
encoder_[ 6] = create_encoder<code_length, 6>(field, gen_poly_index);
encoder_[ 8] = create_encoder<code_length, 8>(field, gen_poly_index);
encoder_[ 10] = create_encoder<code_length, 10>(field, gen_poly_index);
encoder_[ 12] = create_encoder<code_length, 12>(field, gen_poly_index);
encoder_[ 14] = create_encoder<code_length, 14>(field, gen_poly_index);
encoder_[ 16] = create_encoder<code_length, 16>(field, gen_poly_index);
encoder_[ 18] = create_encoder<code_length, 18>(field, gen_poly_index);
encoder_[ 20] = create_encoder<code_length, 20>(field, gen_poly_index);
encoder_[ 22] = create_encoder<code_length, 22>(field, gen_poly_index);
encoder_[ 24] = create_encoder<code_length, 24>(field, gen_poly_index);
encoder_[ 26] = create_encoder<code_length, 26>(field, gen_poly_index);
encoder_[ 28] = create_encoder<code_length, 28>(field, gen_poly_index);
encoder_[ 30] = create_encoder<code_length, 30>(field, gen_poly_index);
encoder_[ 32] = create_encoder<code_length, 32>(field, gen_poly_index);
encoder_[ 64] = create_encoder<code_length, 64>(field, gen_poly_index);
encoder_[ 80] = create_encoder<code_length, 80>(field, gen_poly_index);
encoder_[ 96] = create_encoder<code_length, 96>(field, gen_poly_index);
encoder_[128] = create_encoder<code_length,128>(field, gen_poly_index);
decoder_[ 2] = create_decoder<code_length, 2>(field, gen_poly_index);
decoder_[ 4] = create_decoder<code_length, 4>(field, gen_poly_index);
decoder_[ 6] = create_decoder<code_length, 6>(field, gen_poly_index);
decoder_[ 8] = create_decoder<code_length, 8>(field, gen_poly_index);
decoder_[ 10] = create_decoder<code_length, 10>(field, gen_poly_index);
decoder_[ 12] = create_decoder<code_length, 12>(field, gen_poly_index);
decoder_[ 14] = create_decoder<code_length, 14>(field, gen_poly_index);
decoder_[ 16] = create_decoder<code_length, 16>(field, gen_poly_index);
decoder_[ 18] = create_decoder<code_length, 18>(field, gen_poly_index);
decoder_[ 20] = create_decoder<code_length, 20>(field, gen_poly_index);
decoder_[ 22] = create_decoder<code_length, 22>(field, gen_poly_index);
decoder_[ 24] = create_decoder<code_length, 24>(field, gen_poly_index);
decoder_[ 26] = create_decoder<code_length, 26>(field, gen_poly_index);
decoder_[ 28] = create_decoder<code_length, 28>(field, gen_poly_index);
decoder_[ 30] = create_decoder<code_length, 30>(field, gen_poly_index);
decoder_[ 32] = create_decoder<code_length, 32>(field, gen_poly_index);
decoder_[ 64] = create_decoder<code_length, 64>(field, gen_poly_index);
decoder_[ 80] = create_decoder<code_length, 80>(field, gen_poly_index);
decoder_[ 96] = create_decoder<code_length, 96>(field, gen_poly_index);
decoder_[128] = create_decoder<code_length,128>(field, gen_poly_index);
}
~general_codec()
{
delete static_cast<reed_solomon::encoder<code_length, 2>*>(encoder_[ 2]);
delete static_cast<reed_solomon::encoder<code_length, 4>*>(encoder_[ 4]);
delete static_cast<reed_solomon::encoder<code_length, 6>*>(encoder_[ 6]);
delete static_cast<reed_solomon::encoder<code_length, 8>*>(encoder_[ 8]);
delete static_cast<reed_solomon::encoder<code_length, 10>*>(encoder_[ 10]);
delete static_cast<reed_solomon::encoder<code_length, 12>*>(encoder_[ 12]);
delete static_cast<reed_solomon::encoder<code_length, 14>*>(encoder_[ 14]);
delete static_cast<reed_solomon::encoder<code_length, 16>*>(encoder_[ 16]);
delete static_cast<reed_solomon::encoder<code_length, 18>*>(encoder_[ 18]);
delete static_cast<reed_solomon::encoder<code_length, 20>*>(encoder_[ 20]);
delete static_cast<reed_solomon::encoder<code_length, 22>*>(encoder_[ 22]);
delete static_cast<reed_solomon::encoder<code_length, 24>*>(encoder_[ 24]);
delete static_cast<reed_solomon::encoder<code_length, 26>*>(encoder_[ 26]);
delete static_cast<reed_solomon::encoder<code_length, 28>*>(encoder_[ 28]);
delete static_cast<reed_solomon::encoder<code_length, 30>*>(encoder_[ 30]);
delete static_cast<reed_solomon::encoder<code_length, 32>*>(encoder_[ 32]);
delete static_cast<reed_solomon::encoder<code_length, 64>*>(encoder_[ 64]);
delete static_cast<reed_solomon::encoder<code_length, 80>*>(encoder_[ 80]);
delete static_cast<reed_solomon::encoder<code_length, 96>*>(encoder_[ 96]);
delete static_cast<reed_solomon::encoder<code_length,128>*>(encoder_[128]);
delete static_cast<reed_solomon::decoder<code_length, 2>*>(decoder_[ 2]);
delete static_cast<reed_solomon::decoder<code_length, 4>*>(decoder_[ 4]);
delete static_cast<reed_solomon::decoder<code_length, 6>*>(decoder_[ 6]);
delete static_cast<reed_solomon::decoder<code_length, 8>*>(decoder_[ 8]);
delete static_cast<reed_solomon::decoder<code_length, 10>*>(decoder_[ 10]);
delete static_cast<reed_solomon::decoder<code_length, 12>*>(decoder_[ 12]);
delete static_cast<reed_solomon::decoder<code_length, 14>*>(decoder_[ 14]);
delete static_cast<reed_solomon::decoder<code_length, 16>*>(decoder_[ 16]);
delete static_cast<reed_solomon::decoder<code_length, 18>*>(decoder_[ 18]);
delete static_cast<reed_solomon::decoder<code_length, 20>*>(decoder_[ 20]);
delete static_cast<reed_solomon::decoder<code_length, 22>*>(decoder_[ 22]);
delete static_cast<reed_solomon::decoder<code_length, 24>*>(decoder_[ 24]);
delete static_cast<reed_solomon::decoder<code_length, 26>*>(decoder_[ 26]);
delete static_cast<reed_solomon::decoder<code_length, 28>*>(decoder_[ 28]);
delete static_cast<reed_solomon::decoder<code_length, 30>*>(decoder_[ 30]);
delete static_cast<reed_solomon::decoder<code_length, 32>*>(decoder_[ 32]);
delete static_cast<reed_solomon::decoder<code_length, 64>*>(decoder_[ 64]);
delete static_cast<reed_solomon::decoder<code_length, 80>*>(decoder_[ 80]);
delete static_cast<reed_solomon::decoder<code_length, 96>*>(decoder_[ 96]);
delete static_cast<reed_solomon::decoder<code_length,128>*>(decoder_[128]);
}
template <typename Block>
bool encode(Block& block) const
{
/*
cl : code length
fl : fec length
*/
typedef reed_solomon::encoder<Block::trait::code_length,Block::trait::fec_length> encoder_type;
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
if (encoder_[Block::trait::fec_length] == 0)
return false;
else
return static_cast<encoder_type*>(encoder_[Block::trait::fec_length])->encode(block);
}
template <typename Block>
bool decode(Block& block) const
{
typedef reed_solomon::decoder<Block::trait::code_length,Block::trait::fec_length> decoder_type;
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
if (decoder_[Block::trait::fec_length] == 0)
return false;
else
return static_cast<decoder_type*>(decoder_[Block::trait::fec_length])->decode(block);
}
private:
void* encoder_[max_fec_length + 1];
void* decoder_[max_fec_length + 1];
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,639 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
#include <cstddef>
#include <iostream>
#include <string>
#include "schifra_reed_solomon_block.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
inline void interleave(block<code_length,fec_length> (&block_stack)[code_length])
{
for (std::size_t i = 0; i < code_length; ++i)
{
for (std::size_t j = i + 1; j < code_length; ++j)
{
typename block<code_length,fec_length>::symbol_type tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void interleave(block<code_length,fec_length> (&block_stack)[row_count])
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < code_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void interleave(block<code_length,fec_length,row_count> (&block_stack)[row_count],
const std::size_t partial_code_length)
{
if (partial_code_length == code_length)
{
interleave<code_length,fec_length,row_count>(block_stack);
}
else
{
block<code_length,fec_length,row_count> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_code_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_code_length; index < code_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == code_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < code_length - fec_length; ++index)
{
block_stack[row].data[index] = auxiliary_stack[row].data[index];
}
for (std::size_t index = 0; index < fec_length; ++index)
{
block_stack[row].fec[index] = auxiliary_stack[row].fec[index];
}
}
for (std::size_t index = 0; index < partial_code_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> (&block_stack)[block_length])
{
for (std::size_t i = 0; i < block_length; ++i)
{
for (std::size_t j = i + 1; j < block_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void interleave(data_block<T,block_length> (&block_stack)[row_count])
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void interleave(data_block<T,block_length> (&block_stack)[row_count],
const std::size_t partial_block_length)
{
if (partial_block_length == block_length)
{
interleave<T,block_length,row_count>(block_stack);
}
else
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_block_length; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> block_stack[],
const std::size_t row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length>
inline void interleave(data_block<T,block_length> block_stack[],
const std::size_t row_count,
const std::size_t partial_block_length)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t index = 0; index < partial_block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t index = partial_block_length; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count - 1; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = 0;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
delete[] auxiliary_stack;
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count])
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < code_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
}
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count],
const std::size_t partial_code_length)
{
if (partial_code_length == code_length)
{
deinterleave<code_length,fec_length,row_count>(block_stack);
}
else
{
block<code_length,fec_length> auxiliary_stack[row_count];
std::size_t aux_row1 = 0;
std::size_t aux_index1 = 0;
std::size_t aux_row2 = 0;
std::size_t aux_index2 = 0;
for (std::size_t i = 0; i < partial_code_length * row_count; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == row_count)
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == code_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t i = 0; aux_index1 < code_length; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == (row_count - 1))
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == code_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < code_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_code_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
}
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> (&block_stack)[block_length])
{
data_block<T,block_length> auxiliary_stack[block_length];
for (std::size_t row = 0; row < block_length; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[index][row] = block_stack[row][index];
}
}
copy<T,block_length,block_length>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length, std::size_t row_count>
inline void deinterleave(data_block<T,block_length> (&block_stack)[row_count])
{
data_block<T,block_length> auxiliary_stack[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> block_stack[],
const std::size_t row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = 0;
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_row == row_count)
{
aux_row = 0;
aux_index++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length>
inline void deinterleave(data_block<T,block_length> block_stack[],
const std::size_t row_count,
const std::size_t partial_block_length)
{
if (row_count == 1) return;
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row1 = 0;
std::size_t aux_index1 = 0;
std::size_t aux_row2 = 0;
std::size_t aux_index2 = 0;
for (std::size_t i = 0; i < partial_block_length * row_count; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == row_count)
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == block_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t i = 0; aux_index1 < block_length; ++i)
{
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
if (++aux_row1 == (row_count - 1))
{
aux_row1 = 0;
aux_index1++;
}
if (++aux_index2 == block_length)
{
aux_index2 = 0;
aux_row2++;
}
}
for (std::size_t row = 0; row < row_count - 1; ++row)
{
for (std::size_t index = 0; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
for (std::size_t index = 0; index < partial_block_length; ++index)
{
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t block_length, std::size_t skip_columns>
inline void interleave_columnskip(data_block<T,block_length>* block_stack)
{
for (std::size_t i = 0; i < block_length; ++i)
{
for (std::size_t j = i + 1; j < block_length; ++j)
{
std::size_t x1 = i + skip_columns;
std::size_t x2 = j + skip_columns;
T tmp = block_stack[i][x2];
block_stack[i][x2] = block_stack[j][x1];
block_stack[j][x1] = tmp;
}
}
}
template <typename T, std::size_t block_length, std::size_t skip_columns>
inline void interleave_columnskip(data_block<T,block_length>* block_stack, const std::size_t& row_count)
{
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
std::size_t aux_row = 0;
std::size_t aux_index = skip_columns;
for (std::size_t index = skip_columns; index < block_length; ++index)
{
for (std::size_t row = 0; row < row_count; ++row)
{
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
if (++aux_index == block_length)
{
aux_index = skip_columns;
aux_row++;
}
}
}
for (std::size_t row = 0; row < row_count; ++row)
{
for (std::size_t index = skip_columns; index < block_length; ++index)
{
block_stack[row][index] = auxiliary_stack[row][index];
}
}
delete[] auxiliary_stack;
}
template <typename T, std::size_t data_length>
inline void interleave(T* block_stack[data_length])
{
for (std::size_t i = 0; i < data_length; ++i)
{
for (std::size_t j = i + 1; j < data_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
template <typename T, std::size_t data_length, std::size_t skip_columns>
inline void interleave_columnskip(T* block_stack[data_length])
{
for (std::size_t i = skip_columns; i < data_length; ++i)
{
for (std::size_t j = i + 1; j < data_length; ++j)
{
T tmp = block_stack[i][j];
block_stack[i][j] = block_stack[j][i];
block_stack[j][i] = tmp;
}
}
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,238 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
#include <cstddef>
#include <iostream>
#include <fstream>
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_interleaving.hpp"
#include "schifra_reed_solomon_bitio.hpp"
#include "schifra_ecc_traits.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class square_product_code_encoder
{
public:
typedef encoder<code_length,fec_length> encoder_type;
typedef block<code_length,fec_length> block_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef unsigned char data_type;
typedef data_type* data_ptr_type;
enum { data_size = data_length * data_length };
enum { total_size = code_length * code_length };
square_product_code_encoder(const encoder_type& enc)
: encoder_(enc)
{}
bool encode(data_ptr_type data)
{
data_ptr_type curr_data_ptr = data;
for (std::size_t row = 0; row < data_length; ++row, curr_data_ptr += data_length)
{
copy(curr_data_ptr, data_length, block_stack_[row]);
if (!encoder_.encode(block_stack_[row]))
{
return false;
}
}
block_type vertical_block;
for (std::size_t col = 0; col < code_length; ++col)
{
for (std::size_t row = 0; row < data_length; ++row)
{
vertical_block[row] = block_stack_[row][col];
}
if (!encoder_.encode(vertical_block))
{
return false;
}
for (std::size_t fec_index = 0; fec_index < fec_length; ++fec_index)
{
block_stack_[data_length + fec_index].fec(fec_index) = vertical_block.fec(fec_index);
}
}
return true;
}
bool encode_and_interleave(data_ptr_type data)
{
if (!encode(data))
{
return false;
}
interleave<code_length,fec_length>(block_stack_);
return true;
}
void output(data_ptr_type output_data)
{
for (std::size_t row = 0; row < code_length; ++row, output_data += code_length)
{
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,code_length);
}
}
void clear()
{
for (std::size_t i = 0; i < code_length; ++i)
{
block_stack_[i].clear();
}
}
private:
square_product_code_encoder(const square_product_code_encoder& spce);
square_product_code_encoder& operator=(const square_product_code_encoder& spce);
block_type block_stack_[code_length];
const encoder_type& encoder_;
};
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
class square_product_code_decoder
{
public:
typedef decoder<code_length,fec_length> decoder_type;
typedef block<code_length,fec_length> block_type;
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
typedef unsigned char data_type;
typedef data_type* data_ptr_type;
enum { data_size = data_length * data_length };
enum { total_size = code_length * code_length };
square_product_code_decoder(const decoder_type& decoder)
: decoder_(decoder)
{}
void decode(data_ptr_type data)
{
copy_proxy(data);
decode_proxy();
}
void deinterleave_and_decode(data_ptr_type data)
{
copy_proxy(data);
interleave<code_length,fec_length>(block_stack_);
decode_proxy();
}
void output(data_ptr_type output_data)
{
for (std::size_t row = 0; row < data_length; ++row, output_data += data_length)
{
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,data_length);
}
}
void clear()
{
for (std::size_t i = 0; i < code_length; ++i)
{
block_stack_[i].clear();
}
}
private:
square_product_code_decoder(const square_product_code_decoder& spcd);
square_product_code_decoder& operator=(const square_product_code_decoder& spcd);
void copy_proxy(data_ptr_type data)
{
for (std::size_t row = 0; row < code_length; ++row, data += code_length)
{
bitio::convert_data_to_symbol<traits::symbol<code_length>::size>(data,code_length,block_stack_[row].data);
}
}
void decode_proxy()
{
bool first_iteration_failure = false;
for (std::size_t row = 0; row < data_length; ++row)
{
if (!decoder_.decode(block_stack_[row]))
{
first_iteration_failure = true;
}
}
if (!first_iteration_failure)
{
/*
Either no errors detected or all errors have
been detected and corrected.
*/
return;
}
block_type vertical_block;
for (std::size_t col = 0; col < code_length; ++col)
{
for (std::size_t row = 0; row < data_length; ++row)
{
vertical_block[row] = block_stack_[row][col];
}
decoder_.decode(vertical_block);
}
}
block_type block_stack_[code_length];
const decoder_type& decoder_;
};
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,411 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
#define INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
#include <cstddef>
#include <cstdio>
#include <iostream>
#include <string>
#include "schifra_galois_field.hpp"
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
#include "schifra_reed_solomon_block.hpp"
#include "schifra_reed_solomon_encoder.hpp"
#include "schifra_reed_solomon_decoder.hpp"
#include "schifra_reed_solomon_file_encoder.hpp"
#include "schifra_reed_solomon_file_decoder.hpp"
#include "schifra_error_processes.hpp"
#include "schifra_utilities.hpp"
namespace schifra
{
namespace reed_solomon
{
template <std::size_t code_length, std::size_t fec_length>
void create_messages(const encoder<code_length,fec_length>& rs_encoder,
std::vector< block<code_length,fec_length> >& original_block_list,
const bool full_test_set = false)
{
const std::size_t data_length = code_length - fec_length;
std::vector<std::string> message_list;
if (full_test_set)
{
for (unsigned int i = 0; i < 256; ++i)
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(i)));
}
}
else
{
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
}
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = static_cast<unsigned char>(i);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < data_length; ++i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
for (int i = data_length - 1; i >= 0; --i)
{
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0xFF);
}
message_list.push_back(tmp_str);
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF)) ;
for (std::size_t i = 0; i < (data_length >> 1); ++i)
{
tmp_str[i] = static_cast<unsigned char>(0x00);
}
message_list.push_back(tmp_str);
for (std::size_t i = 0; i < message_list.size(); ++i)
{
block<code_length,fec_length> current_block;
rs_encoder.encode(message_list[i],current_block);
original_block_list.push_back(current_block);
}
}
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length,
typename RSEncoder = encoder<code_length,fec_length>,
typename RSDecoder = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
struct all_errors_decoder_speed_test
{
public:
all_errors_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
{
galois::field field(field_descriptor,prim_poly_size,prim_poly);
galois::field_polynomial generator_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
generator_polynomial)
)
{
return;
}
RSEncoder rs_encoder(field,generator_polynomial);
RSDecoder rs_decoder(field,gen_poly_index);
std::vector< block<code_length,fec_length> > original_block;
create_messages<code_length,fec_length>(rs_encoder,original_block);
std::vector<block<code_length,fec_length> > rs_block;
std::vector<std::size_t> block_index_list;
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
{
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block<code_length,fec_length> block = original_block[block_index];
corrupt_message_all_errors(block,error_count,start_position,1);
rs_block.push_back(block);
block_index_list.push_back(block_index);
}
}
}
const std::size_t max_iterations = 100;
std::size_t blocks_decoded = 0;
std::size_t block_failures = 0;
schifra::utils::timer timer;
timer.start();
for (std::size_t j = 0; j < max_iterations; ++j)
{
for (std::size_t i = 0; i < rs_block.size(); ++i)
{
if (!rs_decoder.decode(rs_block[i]))
{
std::cout << "Decoding Failure!" << std::endl;
block_failures++;
}
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
{
std::cout << "Error Correcting Failure!" << std::endl;
block_failures++;
}
else
blocks_decoded++;
}
}
timer.stop();
double time = timer.time();
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
print_codec_properties();
if (block_failures == 0)
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
static_cast<int>(blocks_decoded),
time,
mbps);
else
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
}
void print_codec_properties()
{
printf("[All Errors Test] Codec: RS(%03d,%03d,%03d) ",
static_cast<int>(code_length),
static_cast<int>(data_length),
static_cast<int>(fec_length));
}
};
template <std::size_t field_descriptor,
std::size_t gen_poly_index,
std::size_t code_length,
std::size_t fec_length,
typename RSEncoder = encoder<code_length,fec_length>,
typename RSDecoder = decoder<code_length,fec_length>,
std::size_t data_length = code_length - fec_length>
struct all_erasures_decoder_speed_test
{
public:
all_erasures_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
{
galois::field field(field_descriptor,prim_poly_size,prim_poly);
galois::field_polynomial generator_polynomial(field);
if (
!make_sequential_root_generator_polynomial(field,
gen_poly_index,
fec_length,
generator_polynomial)
)
{
return;
}
RSEncoder rs_encoder(field,generator_polynomial);
RSDecoder rs_decoder(field,gen_poly_index);
std::vector< block<code_length,fec_length> > original_block;
create_messages<code_length,fec_length>(rs_encoder,original_block);
std::vector<block<code_length,fec_length> > rs_block;
std::vector<erasure_locations_t> erasure_list;
std::vector<std::size_t> block_index_list;
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
{
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
{
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
{
block<code_length,fec_length> block = original_block[block_index];
erasure_locations_t erasures;
corrupt_message_all_erasures(block,erasures,erasure_count,start_position,1);
if (erasure_count != erasures.size())
{
std::cout << "all_erasures_decoder_speed_test() - Failed to properly generate erasures list. Details:";
std::cout << "(" << block_index << "," << erasure_count << "," << start_position << ")" << std::endl;
}
rs_block.push_back(block);
erasure_list.push_back(erasures);
block_index_list.push_back(block_index);
}
}
}
const std::size_t max_iterations = 100;
std::size_t blocks_decoded = 0;
std::size_t block_failures = 0;
schifra::utils::timer timer;
timer.start();
for (std::size_t j = 0; j < max_iterations; ++j)
{
for (std::size_t i = 0; i < rs_block.size(); ++i)
{
if (!rs_decoder.decode(rs_block[i],erasure_list[i]))
{
std::cout << "Decoding Failure!" << std::endl;
block_failures++;
}
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
{
std::cout << "Error Correcting Failure!" << std::endl;
block_failures++;
}
else
blocks_decoded++;
}
}
timer.stop();
double time = timer.time();
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
print_codec_properties();
if (block_failures == 0)
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
static_cast<int>(blocks_decoded),
time,
mbps);
else
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
}
void print_codec_properties()
{
printf("[All Erasures Test] Codec: RS(%03d,%03d,%03d) ",
static_cast<int>(code_length),
static_cast<int>(data_length),
static_cast<int>(fec_length));
}
};
void speed_test_00()
{
all_errors_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_errors_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
}
void speed_test_01()
{
all_erasures_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
all_erasures_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
}
} // namespace reed_solomon
} // namespace schifra
#endif

View File

@ -0,0 +1,64 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
#define INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
#include <cstddef>
#include "schifra_galois_field.hpp"
#include "schifra_galois_field_element.hpp"
#include "schifra_galois_field_polynomial.hpp"
namespace schifra
{
inline bool make_sequential_root_generator_polynomial(const galois::field& field,
const std::size_t initial_index,
const std::size_t num_elements,
galois::field_polynomial& generator_polynomial)
{
if (
(initial_index >= field.size()) ||
((initial_index + num_elements) > field.size())
)
{
return false;
}
galois::field_element alpha(field, 2);
galois::field_polynomial X = galois::generate_X(field);
generator_polynomial = galois::field_element(field, 1);
for (std::size_t i = initial_index; i < (initial_index + num_elements); ++i)
{
generator_polynomial *= (X + (alpha ^ static_cast<galois::field_symbol>(i)));
}
return true;
}
} // namespace schifra
#endif

View File

@ -0,0 +1,198 @@
/*
(**************************************************************************)
(* *)
(* Schifra *)
(* Reed-Solomon Error Correcting Code Library *)
(* *)
(* Release Version 0.0.1 *)
(* http://www.schifra.com *)
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
(* *)
(* The Schifra Reed-Solomon error correcting code library and all its *)
(* components are supplied under the terms of the General Schifra License *)
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
(* code library and all its components may not be copied or disclosed *)
(* except in accordance with the terms of that agreement. *)
(* *)
(* URL: http://www.schifra.com/license.html *)
(* *)
(**************************************************************************)
*/
#ifndef INCLUDE_SCHIFRA_UTILITES_HPP
#define INCLUDE_SCHIFRA_UTILITES_HPP
#include <cstddef>
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#include <windows.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#endif
namespace schifra
{
namespace utils
{
const std::size_t high_bits_in_char[256] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};
template <typename T>
inline std::size_t hamming_distance_element(const T v1, const T v2)
{
std::size_t distance = 0;
const unsigned char* it1 = reinterpret_cast<const unsigned char*>(&v1);
const unsigned char* it2 = reinterpret_cast<const unsigned char*>(&v2);
for (std::size_t i = 0; i < sizeof(T); ++i, ++it1, ++it2)
{
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
}
return distance;
}
inline std::size_t hamming_distance(const unsigned char data1[], const unsigned char data2[], const std::size_t length)
{
std::size_t distance = 0;
const unsigned char* it1 = data1;
const unsigned char* it2 = data2;
for (std::size_t i = 0; i < length; ++i, ++it1, ++it2)
{
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
}
return distance;
}
template <typename ForwardIterator>
inline std::size_t hamming_distance(ForwardIterator it1_begin, ForwardIterator it2_begin, ForwardIterator it1_end)
{
std::size_t distance = 0;
ForwardIterator it1 = it1_begin;
ForwardIterator it2 = it2_begin;
for (; it1 != it1_end; ++it1, ++it2)
{
distance += hamming_distance_element(*it1,*it2);
}
return distance;
}
class timer
{
public:
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
timer()
: in_use_(false)
{
QueryPerformanceFrequency(&clock_frequency_);
}
inline void start()
{
in_use_ = true;
QueryPerformanceCounter(&start_time_);
}
inline void stop()
{
QueryPerformanceCounter(&stop_time_);
in_use_ = false;
}
inline double time() const
{
return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart);
}
#else
timer()
: in_use_(false)
{
start_time_.tv_sec = 0;
start_time_.tv_usec = 0;
stop_time_.tv_sec = 0;
stop_time_.tv_usec = 0;
}
inline void start()
{
in_use_ = true;
gettimeofday(&start_time_,0);
}
inline void stop()
{
gettimeofday(&stop_time_, 0);
in_use_ = false;
}
inline unsigned long long int usec_time() const
{
if (!in_use_)
{
if (stop_time_.tv_sec >= start_time_.tv_sec)
{
return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) +
(stop_time_.tv_usec - start_time_.tv_usec);
}
else
return std::numeric_limits<unsigned long long int>::max();
}
else
return std::numeric_limits<unsigned long long int>::max();
}
inline double time() const
{
return usec_time() * 0.000001;
}
#endif
inline bool in_use() const
{
return in_use_;
}
private:
bool in_use_;
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
LARGE_INTEGER start_time_;
LARGE_INTEGER stop_time_;
LARGE_INTEGER clock_frequency_;
#else
struct timeval start_time_;
struct timeval stop_time_;
#endif
};
} // namespace utils
} // namespace schifra
#endif

67
modem/fec_fast.c Normal file
View File

@ -0,0 +1,67 @@
/*
* 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);
}

140
modem/fft.c Normal file
View File

@ -0,0 +1,140 @@
/*
* 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 <fftw3.h>
#include <math.h>
#define AUDIOSAMPLERATE 8000
double *din = NULL; // input data for fft
fftw_complex *cpout = NULL; // ouput data from fft
fftw_plan plan = NULL;
#define fft_rate (AUDIOSAMPLERATE / 10) // resolution: 10 Hz
int fftidx = 0;
int fftcnt = fft_rate/2+1; // number of output values
uint16_t fftout[AUDIOSAMPLERATE / 10/2+1];
uint16_t *make_waterfall(uint8_t *pdata, int len, int *retlen)
{
int fftrdy = 0;
// get the real sample in float (imag is not required for the FFT)
int re=0;
// GR sends 8 Bytes containing 4x 0x000003e8 (marker) and 4x input-samples (real integer)
#define dlen 8
static uint8_t rbuf[dlen];
for(int i=0; i<len; i++)
{
// insert new byte in rbuf
for(int sh = (dlen-1); sh > 0; sh--)
rbuf[sh] = rbuf[sh - 1];
rbuf[0] = pdata[i];
// check for BIG/LITTLE endian
if(rbuf[0] == 0 && rbuf[1] == 0 && rbuf[2] == 3 && rbuf[3] == 0xe8)
{
re = rbuf[4];
re <<= 24;
re += rbuf[5];
re <<= 16;
re += rbuf[6];
re <<= 8;
re += rbuf[7];
}
else if(rbuf[0] == 0xe8 && rbuf[1] == 3 && rbuf[2] == 0 && rbuf[3] == 0)
{
re = rbuf[7];
re <<= 24;
re += rbuf[6];
re <<= 16;
re += rbuf[5];
re <<= 8;
re += rbuf[4];
}
else
continue;
// the value was scaled in GR by 2^24 = 16777216
// in order to send it in an INT
// undo this scaling
float fre = (float)re / 16777216;
// fre are the float samples
// fill into the fft input buffer
din[fftidx++] = fre;
if(fftidx == fft_rate)
{
fftidx = 0;
// the fft buffer is full, execute the FFT
fftw_execute(plan);
for (int j = 0; j < fftcnt; j++)
{
// calculate absolute value (magnitute without phase)
float fre = cpout[j][0];
float fim = cpout[j][1];
float mag = sqrt((fre * fre) + (fim * fim));
fftout[j] = (uint16_t)mag;
fftrdy = 1;
}
}
}
if(fftrdy == 1)
{
*retlen = fftcnt;
return fftout;
}
return NULL;
}
void init_fft()
{
char fn[300];
sprintf(fn, "capture_fft_%d", fft_rate); // wisdom file for each capture rate
fftw_import_wisdom_from_filename(fn);
din = (double *)fftw_malloc(sizeof(double) * fft_rate);
cpout = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * fft_rate);
plan = fftw_plan_dft_r2c_1d(fft_rate, din, cpout, FFTW_MEASURE);
fftw_export_wisdom_to_filename(fn);
}
void exit_fft()
{
if(plan) fftw_destroy_plan(plan);
if(din) fftw_free(din);
if(cpout) fftw_free(cpout);
}

323
modem/frame_packer.c Normal file
View File

@ -0,0 +1,323 @@
/*
* 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"
void Insert(uint8_t bit);
uint8_t *FindDatablock();
uint8_t rxbuffer[UDPBLOCKLEN*8/2+100]; // 3...bits per symbol QPSK, enough space also for QPSK and 8PSK, +100 ... reserve, just to be sure
uint8_t rx_status = 0;
int framecounter = 0;
int lastframenum = 0;
// header for TX,
uint8_t TXheaderbytes[HEADERLEN] = {0x53, 0xe1, 0xa6};
// corresponds to these QPSK symbols:
// bits: 01010011 11100001 10100110
// QPSK:
// syms: 1 1 0 3 3 2 0 1 2 2 1 2
// 8PSK:
// syms: 2 4 7 6 0 6 4 6
// QPSK
// each header has 12 symbols
// we have 4 constellations
uint8_t QPSK_headertab[4][HEADERLEN*8/2];
// 8PSK
// each header has 12 symbols
// we have 8 constellations
uint8_t _8PSK_headertab[8][HEADERLEN*8/3];
// init header tables
void init_packer()
{
// create the QPSK symbol table for the HEADER
// in all possible rotations
convertBytesToSyms_QPSK(TXheaderbytes, QPSK_headertab[0], 3);
for(int i=1; i<4; i++)
rotateQPSKsyms(QPSK_headertab[i-1], QPSK_headertab[i], 12);
// create the 8PSK symbol table for the HEADER
// in all possible rotations
convertBytesToSyms_8PSK(TXheaderbytes, _8PSK_headertab[0], 3);
for(int i=1; i<8; i++)
rotate8PSKsyms(_8PSK_headertab[i-1], _8PSK_headertab[i], 8);
}
// packs a payload into an udp data block
// the payload has a size of PAYLOADLEN
// type ... inserted in the "frame type information" field
// status ... specifies first/last frame of a data stream
uint8_t *Pack(uint8_t *payload, int type, int status, int *plen)
{
FRAME frame; // raw frame without fec
// polulate the raw frame
// make the frame counter
if(status & (1<<4))
framecounter = 0; // first block of a stream
else
framecounter++;
// insert frame counter and status bits
frame.counter_LSB = framecounter & 0xff;
int framecnt_MSB = (framecounter >> 8) & 0x03; // Bit 8+9 of framecounter
frame.status = framecnt_MSB << 6;
frame.status += ((status & 0x03)<<4);
frame.status += (type & 0x0f);
// insert the payload
memcpy(frame.payload, payload, PAYLOADLEN);
// calculate and insert the CRC16
uint16_t crc16 = Crc16_messagecalc(CRC16TX,(uint8_t *)(&frame), CRCSECUREDLEN);
frame.crc16_MSB = (uint8_t)(crc16 >> 8);
frame.crc16_LSB = (uint8_t)(crc16 & 0xff);
// make the final arry for transmission
static uint8_t txblock[UDPBLOCKLEN];
// calculate the fec and insert into txblock (leave space for the header)
GetFEC((uint8_t *)(&frame), DATABLOCKLEN, txblock+HEADERLEN);
// scramble
TX_Scramble(txblock+HEADERLEN, FECBLOCKLEN); // scramble all data
// insert the header
memcpy(txblock,TXheaderbytes,HEADERLEN);
/* test pattern
* for(int i=0; i<FECBLOCKLEN; i+=2)
{
*(txblock+HEADERLEN+i) = i;
*(txblock+HEADERLEN+i+1) = 0xf0;
}*/
*plen = UDPBLOCKLEN;
return txblock;
}
/*void store(int newfile, uint8_t * d, int len)
{
FILE *fp;
if(newfile)
fp = fopen("hdr","w");
else
fp = fopen("hdr","a");
if(fp)
{
for(int i=0; i<len; i++)
fprintf(fp,"%02X ",d[i]);
fprintf(fp,"\n");
fclose(fp);
}
}*/
#define MAXHEADERRS 0
/*
* Header erros will not cause any data errors because the CRC will filter out
* false header detects,
* but it will cause higher CPU load due to excessive execution of FEC and CRC
*/
int seekHeadersyms()
{
if(constellationSize == 4)
{
// QPSK
for(int tab=0; tab<4; tab++)
{
int errs = 0;
for(int i=0; i<HEADERLEN*8/2; i++)
{
if(rxbuffer[i] != QPSK_headertab[tab][i])
{
errs++;
}
}
if(errs <= MAXHEADERRS) return tab;
}
}
else
{
// 8PSK
for(int tab=0; tab<8; tab++)
{
int errs = 0;
for(int i=0; i<HEADERLEN*8/3; i++)
{
if(rxbuffer[i] != _8PSK_headertab[tab][i])
{
errs++;
}
}
if(errs <= MAXHEADERRS) return tab;
}
}
return -1;
}
// unpacks a received data frame
// pdata, len ... symbols received from the modem
// returns ... payload, one full frame
uint8_t *unpack_data(uint8_t *rxd, int len)
{
int framerdy = 0;
static uint8_t payload[PAYLOADLEN+10];
rx_status = 0;
// shift all received symbols through rxbuffer
// until a header is detected
for(int sym=0; sym<len; sym++)
{
// shift rxbuffer right by one symbol (=byte)
// frmlen ... number of symbols
int frmlen = UDPBLOCKLEN*8/bitsPerSymbol;
memmove(rxbuffer,rxbuffer+1,frmlen-1);
// insert new symbol at the top
rxbuffer[frmlen-1] = rxd[sym];
//showbytestring((char*)"rx: ",rxbuffer,30);
int rotations = seekHeadersyms();
if(rotations != -1)
{
//printf("Header found, rotation: %d\n",rotations);
// rxbuffer contains all symbols of the received frame
// convert to bytes
uint8_t *rxbytes = NULL;
if(constellationSize == 4)
{
uint8_t *backbuf = rotateBackQPSK(rxbuffer,frmlen,rotations);
rxbytes = convertQPSKSymToBytes(backbuf);
}
else
{
uint8_t *backbuf = rotateBack8PSK(rxbuffer,frmlen,rotations);
rxbytes = convert8PSKSymToBytes(backbuf,UDPBLOCKLEN);
}
if(rxbytes == NULL) return NULL;
// check if we found a data block
uint8_t *pl = getPayload(rxbytes);
if (pl != NULL)
{
memcpy(payload,pl, PAYLOADLEN+10);
framerdy = 1;
}
}
}
if(framerdy)
return payload;
return NULL;
}
// inserts bit per bit into the rxbuffer
// rxbuffer has the size of a complete frame
// so if the header is detected, rxbuffer contains the frame
void Insert(uint8_t bit)
{
if (bit != 0) bit = 1;
// bitshift right
for (int i = 0; i < UDPBLOCKLEN; i++)
{
rxbuffer[i] <<= 1;
if (i == (UDPBLOCKLEN - 1)) break;
uint8_t ov = (uint8_t)(rxbuffer[i + 1] & 0x80);
if (ov != 0) rxbuffer[i] |= 1;
else rxbuffer[i] &= 0xfe;
}
// insert new bit
rxbuffer[UDPBLOCKLEN - 1] &= 0xfe;
rxbuffer[UDPBLOCKLEN - 1] |= (uint8_t)bit;
}
uint8_t *getPayload(uint8_t *rxb)
{
//showbytestring((char *)"orig: ",rxb+HEADERLEN,30);
// unscramble
uint8_t *rxarray = RX_Scramble(rxb+HEADERLEN, FECBLOCKLEN);
// calculate the FEC over the received data
// and fill a frame structure
FRAME frame;
int ret = cfec_Reconstruct(rxarray,(uint8_t *)(&frame));
if(ret == 0)
{
//printf("fec ERROR\n");
return NULL; // fec impossible
}
//printf("fec ok\n");
// check the CRC
uint16_t crc = Crc16_messagecalc(CRC16RX,(uint8_t *)(&frame), CRCSECUREDLEN);
uint16_t rxcrc = frame.crc16_MSB;
rxcrc <<= 8;
rxcrc += frame.crc16_LSB;
if (crc != rxcrc)
{
//printf("crc ERROR\n");
return NULL; // no data found
}
// frame counter verification: lost frame detection
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)
// extract information and build the string for the application
// we have 10 Management Byte then the payload follows
static uint8_t payload[PAYLOADLEN+10];
payload[0] = frame.status & 0x0f; // frame type
payload[1] = (frame.status & 0xc0)>>6; // frame counter MSB
payload[2] = frame.counter_LSB; // frame counter LSB
payload[3] = (frame.status & 0x30)>>4; // first/last frame marker
payload[4] = rx_status; // frame lost information
payload[5] = speed >> 8; // measured line speed
payload[6] = speed;
payload[7] = 0; // free for later use
payload[8] = 0;
payload[9] = 0;
memcpy(payload+10,frame.payload,PAYLOADLEN);
return payload;
}

87
modem/frameformat.h Normal file
View File

@ -0,0 +1,87 @@
/*
* 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.
*
*/
/*
* The total length of the FEC-secured part is 255,
* this is a requirement of the Shifra FEC routine, which
* is the best FEC that I have seen so far, highly recommended
*/
// total "on the air" frame size
// the total length must be a multiple of 2 and 3, so QPSK and 8PSK symbols fit into full bytes
// this is the case with a total length of 258
#define HEADERLEN 3
#define FECBLOCKLEN 255
#define UDPBLOCKLEN (HEADERLEN + FECBLOCKLEN)
/* !!! IMPORTANT for GNU RADIO !!!
* the UDP payload size for TX MUST be exactly UDPBLOCKLEN (258 in this case) or
* the transmitter will not align bits to symbols correctly !
*
* RX payload size is not that important. But the currect size for
* QPSK is UDPBLOCKLEN*8/2 = 1032 and for 8PSK UDPBLOCKLEN*8/3 = 688
* so we can use 344 which are 2 blocks for 8PSK and 3 blocks for QPSK
* */
// size of the elements inside an FECblock
// sum must be 255
#define FECLEN 32 // supported: 16,32,64,128
#define STATUSLEN 2
#define CRCLEN 2
#define PAYLOADLEN (FECBLOCKLEN - FECLEN - CRCLEN - STATUSLEN)
#define CRCSECUREDLEN (PAYLOADLEN + STATUSLEN)
#define DATABLOCKLEN (PAYLOADLEN + CRCLEN + STATUSLEN)
// the header is not FEC secured therefore we give some room for bit
// errors. Only 24 out of the 32 bits must be correct for
// a valid frame detection
extern uint8_t header[HEADERLEN];
typedef struct {
// the total size of the following data must be 255 - 32 = 223 bytes
// the FEC is calculated on FRAME with a length of 223 and returns
// a data block with length 255.
// we use a 10 bits frame counter -> 1024 values
// so we can transmit a data block with a maximum
// size of 255 * 1024 = 261kByte. With the maximum modem speed
// this would be a transmission time of 5,8 minutes which
// is more then enough for a single data block
uint8_t counter_LSB; // lower 8 bits of the frame counter
// the status byte contains these information:
// bit 0..3 : 4 bit (16 values) frame type information
// bit 4 : first frame of a block if "1"
// bit 5 : last frame of a block if "1"
// bit 6..7 : MSB of the frame counter
uint8_t status;
// payload
uint8_t payload[PAYLOADLEN];
// CRC16
uint8_t crc16_MSB;
uint8_t crc16_LSB;
} FRAME;

6
modem/install_gnuradio_ubuntu Executable file
View File

@ -0,0 +1,6 @@
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:gnuradio/gnuradio-releases
sudo apt-get update
sudo apt-get install gnuradio
sudo ldconfig

93
modem/main_helper.c Normal file
View File

@ -0,0 +1,93 @@
/*
* main_helper
* ===========
* by DJ0ABR
*
* functions useful for every main() program start
*
* */
#include "qo100modem.h"
// check if it is already running
int isRunning(char *prgname)
{
int num = 0;
char s[256];
sprintf(s,"ps -e | grep %s",prgname);
FILE *fp = popen(s,"r");
if(fp)
{
// gets the output of the system command
while (fgets(s, sizeof(s)-1, fp) != NULL)
{
if(strstr(s,prgname) && !strstr(s,"grep"))
{
if(++num == 2)
{
printf("%s is already running, do not start twice !",prgname);
pclose(fp);
return 1;
}
}
}
pclose(fp);
}
return 0;
}
// signal handler
void sighandler(int signum)
{
printf("program stopped by signal\n");
stopModem();
exit_fft();
keeprunning = 0;
close(BC_sock_AppToModem);
}
void install_signal_handler()
{
// signal handler, mainly used if the user presses Ctrl-C
struct sigaction sigact;
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGABRT, &sigact, NULL); // assert() error
//sigaction(SIGSEGV, &sigact, NULL);
// switch off signal 13 (broken pipe)
// instead handle the return value of the write or send function
signal(SIGPIPE, SIG_IGN);
}
int run_console_program(char *cmd)
{
printf("executing: %s\n",cmd);
int ret = system(cmd);
if(ret){}
return 0;
}
void showbytestring(char *title, uint8_t *data, int anz)
{
printf("%s. Len %d: ",title,anz);
for(int i=0; i<anz; i++)
printf("%02X ",data[i]);
printf("\n");
}
void showbytestring16(char *title, uint16_t *data, int anz)
{
printf("%s. Len %d: ",title,anz);
for(int i=0; i<anz; i++)
printf("%04X ",data[i]);
printf("\n");
}

18
modem/main_helper.h Normal file
View File

@ -0,0 +1,18 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <wchar.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/file.h>
#include <signal.h>
int isRunning(char *prgname);
void install_signal_handler();
void sighandler(int signum);
int run_console_program(char *cmd);

592
modem/qo100modem.c Normal file
View File

@ -0,0 +1,592 @@
/*
* 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"
int Open_BC_Socket();
void startModem();
void stopModem();
void getMyIP();
void bc_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void appdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void GRdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void GRdata_FFTdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
void GRdata_I_Qdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock);
// threads will exit if set to 0
int keeprunning = 1;
// UDP I/O
int BC_sock_AppToModem = -1;
int DATA_sock_AppToModem = -1;
int DATA_sock_from_GR = -1;
int DATA_sock_FFT_from_GR = -1;
int DATA_sock_I_Q_from_GR = -1;
int UdpBCport_AppToModem = 40131;
int UdpDataPort_AppToModem = 40132;
int UdpDataPort_ModemToApp = 40133;
int UdpDataPort_toGR = 40134;
int UdpDataPort_fromGR = 40135;
int UdpDataPort_fromGR_FFT = 40136;
int UdpDataPort_fromGR_I_Q = 40137;
// op mode depending values
// default mode if not set by the app
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];
char appIP[20] = {0};
int fixappIP = 0;
int restart_modems = 0;
int doNotLoadModems = 0;
int main(int argc, char *argv[])
{
int opt = 0;
char *modemip = NULL;
while ((opt = getopt(argc, argv, "m:e:")) != -1)
{
switch(opt)
{
case 'e':
doNotLoadModems = 1;
break;
case 'm':
modemip = optarg;
memset(appIP,0,20);
int len = strlen(modemip);
if(len < 16)
{
memcpy(appIP,modemip,len);
fixappIP = 1;
printf("Application IP set to: %s\n",modemip);
}
else
{
printf("invalid Application IP: %s\n",modemip);
exit(0);
}
break;
}
}
if(isRunning(ownfilename) == 1)
exit(0);
install_signal_handler();
init_packer();
initFEC();
init_fft();
// 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);
// start udp RX to listen for data from GR Receiver
UdpRxInit(&DATA_sock_from_GR, UdpDataPort_fromGR, &GRdata_rxdata, &keeprunning);
// start udp RX to listen for Audio-Samples (FFT) data from GR Receiver
UdpRxInit(&DATA_sock_FFT_from_GR, UdpDataPort_fromGR_FFT, &GRdata_FFTdata, &keeprunning);
// start udp RX to listen for IQ data from GR Receiver
UdpRxInit(&DATA_sock_I_Q_from_GR, UdpDataPort_fromGR_I_Q, &GRdata_I_Qdata, &keeprunning);
getMyIP();
printf("QO100modem initialised and running\n");
while (keeprunning)
{
if(restart_modems == 1)
{
stopModem();
startModem();
restart_modems = 0;
}
doArraySend();
usleep(100);
}
printf("stopped: %d\n",keeprunning);
close(BC_sock_AppToModem);
return 0;
}
typedef struct {
int audio;
int tx;
int rx;
} SPEEDRATE;
SPEEDRATE sr[9] = {
// QPSK modes
{48000, 32, 8}, // AudioRate, TX-Resampler, RX-Resampler/4
{44100, 28, 7}, // see samprate.ods
{44100, 24, 6},
{48000, 24, 6},
{44100, 20, 5},
{48000, 20, 5},
// 8PSK modes
{44100, 24, 6},
{48000, 24, 6}
};
void startModem()
{
char stx[512];
char srx[512];
if(speedmode >= 0 && speedmode <=5)
{
bitsPerSymbol = 2; // QPSK=2, 8PSK=3
constellationSize = (1<<bitsPerSymbol); // QPSK=4, 8PSK=8
}
else if(speedmode >= 6 && speedmode <=7)
{
bitsPerSymbol = 3; // QPSK=2, 8PSK=3
constellationSize = (1<<bitsPerSymbol); // QPSK=4, 8PSK=8
}
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);
}
// the RX modem needs the app's IP address as a parameter -i ip
if(run_console_program(srx) == -1)
{
printf("cannot start RX modem\n");
exit(0);
}
}
void stopModem()
{
if(doNotLoadModems == 1) return;
printf("stop modem\n");
int ret = system("killall python3");
if(ret){}
// wait until stop job is done
sleep(1);
}
void getMyIP()
{
struct ifaddrs *ifaddr, *ifa;
int s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
printf("getifaddrs error\n");
exit(0);
}
ifa = ifaddr;
while(ifa)
{
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if(ifa->ifa_addr->sa_family==AF_INET)
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(0);
}
strcpy(myIP, host);
if(strncmp(host,"127",3) != 0)
break;
}
ifa = ifa->ifa_next;
}
freeifaddrs(ifaddr);
return;
}
// called from UDP RX thread for Broadcast-search from App
void bc_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
if (len > 0 && pdata[0] == 0x3c)
{
char rxip[20];
strcpy(rxip,inet_ntoa(rxsock->sin_addr));
if(fixappIP == 0)
{
if(strcmp(appIP,rxip))
{
printf("new app IP: %s, restarting modems\n",rxip);
restart_modems = 1;
}
strcpy(appIP,rxip);
//printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
// App searches for the modem IP, mirror the received messages
// so the app gets an UDP message with this local IP
pdata[0] = 3;
sendUDP(appIP,UdpDataPort_ModemToApp,pdata,1);
}
else
{
// appIP is fixed, answer only to this IP
if(!strcmp(appIP,rxip))
{
//printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
restart_modems = 1;
// App searches for the modem IP, mirror the received messages
// so the app gets an UDP message with this local IP
pdata[0] = 3;
sendUDP(appIP,UdpDataPort_ModemToApp,pdata,1);
}
}
}
}
// called by UDP RX thread for data from App
void appdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
uint8_t type = pdata[0];
uint8_t minfo = pdata[1];
if(len != (PAYLOADLEN+2))
{
printf("data from app: wrong length:%d (should be %d)\n",len-2,PAYLOADLEN);
return;
}
// type values: see oscardata config.cs: frame types
if(type == 16)
{
// Byte 1 contains the resampler ratio for TX and RX modem
speedmode = pdata[1];
printf("set speedmode to %d\n",speedmode);
restart_modems = 1;
return;
}
if(type == 17)
{
// auto send file
// TODO
// for testing only:
// simulate sending a text file with 1kB length
int testlen = 100000;
uint8_t arr[testlen];
char c = 'A';
for(int i=0; i<testlen; i++)
{
arr[i] = c;
if(++c>'Z') c='A';
}
arraySend(arr, testlen, 3, (char *)"testfile.txt");
return;
}
if(type == 18)
{
// auto send folder
// TODO
}
if(type == 19)
{
// shut down this modem PC
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);
}
else if((len-2) < PAYLOADLEN)
{
// if not enough data for a full payload add Zeros
uint8_t payload[PAYLOADLEN];
memset(payload,0,PAYLOADLEN);
memcpy(payload,pdata+2,len-2);
toGR_sendData(payload, type, minfo);
}
else
{
toGR_sendData(pdata+2, type, minfo);
}
}
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);
if(txdata != NULL)
{
sendUDP(localIP,UdpDataPort_toGR,txdata,len);
}
}
#define SPEEDMEAN 3
int speedmean = SPEEDMEAN;
int meansumbytes = 0;
int speed = 0;
void measure_speed(int len)
{
struct timeval tv;
static uint64_t lastus = 0;
uint64_t us;
static int sparr[SPEEDMEAN] = {-1};
gettimeofday(&tv, NULL);
us = tv.tv_sec * 1000000 + tv.tv_usec;
if(lastus == 0)
{
lastus = us;
return;
}
uint64_t ts = us-lastus;
// make measurement only if time >= 1s
meansumbytes += len;
if(ts < 5000000)
{
// do not measure
return;
}
// ts ... time in us since last measurement
// divide by the number of bits
ts /= (meansumbytes*8); // time for one bit
int tbit = (int)ts;
int sp1 = 1000000/tbit;
// convert speed of symbols to speed of bits
speed = sp1 * bitsPerSymbol / 8;
int mean = 0;
if(sparr[0] == -1)
{
for(int i=0; i<speedmean; i++)
sparr[i] = speed;
}
else
{
// make mean value
for(int i=speedmean-1; i>0; i--)
sparr[i] = sparr[i-1];
sparr[0] = speed;
}
for(int i=0; i<speedmean; i++)
mean += sparr[i];
mean /= speedmean;
//printf("Speed %d bit/s\n",mean);
lastus = us;
meansumbytes = 0;
}
// called by UDP RX thread for data from GR
void GRdata_rxdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
// raw symbols
measure_speed(len);
uint8_t *pl = unpack_data(pdata, len);
if(pl != NULL)
{
// complete frame received
// send payload to app
uint8_t txpl[PAYLOADLEN+10+1];
memcpy(txpl+1,pl,PAYLOADLEN+10);
txpl[0] = 1; // type 1: payload data follows
sendUDP(appIP,UdpDataPort_ModemToApp,txpl,PAYLOADLEN+10+1);
}
}
// called by UDP RX thread for Audio-Samples (FFT) data from GR
void GRdata_FFTdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
// send IQ data to FFT for waterfall calculation
int fftlen = 0;
uint16_t *fft = make_waterfall(pdata,len, &fftlen);
if(fft != NULL)
{
uint8_t txpl[10000];
if(fftlen > (10000*2+1))
{
printf("txpl too small !!!\n");
return;
}
int bidx = 0;
txpl[bidx++] = 4; // type 4: FFT data follows
for(int i=0; i<fftlen; i++)
{
txpl[bidx++] = fft[i] >> 8;
txpl[bidx++] = fft[i];
}
sendUDP(appIP,UdpDataPort_ModemToApp,txpl,bidx);
}
}
uint8_t lastb[12];
void display_IQ(uint8_t *pdata, int len)
{
for (int i = 0; i < len; i++)
{
// insert new byte in lastb
for (int sh = 12 - 1; sh > 0; sh--)
lastb[sh] = lastb[sh - 1];
lastb[0] = pdata[i];
// test if aligned
// for PC
if (lastb[0] == 0 && lastb[1] == 0 && lastb[2] == 3 && lastb[3] == 0xe8)
{
// we are aligned to a re value
int re = lastb[4];
re <<= 8;
re += lastb[5];
re <<= 8;
re += lastb[6];
re <<= 8;
re += lastb[7];
int im = lastb[8];
im <<= 8;
im += lastb[9];
im <<= 8;
im += lastb[10];
im <<= 8;
im += lastb[11];
double fre = (double)re / 16777216;
double fim = (double)im / 16777216;
printf("re: %f im: %f\n",fre,fim);
}
// and for ARM
else if (lastb[0] == 0xe8 && lastb[1] == 3 && lastb[2] == 0 && lastb[3] == 0)
{
// we are aligned to a re value
int re = lastb[7];
re <<= 8;
re += lastb[6];
re <<= 8;
re += lastb[5];
re <<= 8;
re += lastb[4];
int im = lastb[11];
im <<= 8;
im += lastb[10];
im <<= 8;
im += lastb[9];
im <<= 8;
im += lastb[8];
double fre = (double)re / 16777216;
double fim = (double)im / 16777216;
printf("ARM re: %f im: %f\n",fre,fim);
}
}
}
// called by UDP RX thread for IQ data from GR
void GRdata_I_Qdata(uint8_t *pdata, int len, struct sockaddr_in* rxsock)
{
// these data are floats multiplied by 2^24 and then converted to int
// for testing convert it back and display it
//display_IQ(pdata,len);
// send the data "as is" to app
uint8_t txpl[len+1];
memcpy(txpl+1,pdata,len);
txpl[0] = 5; // type 5: IQ data follows
sendUDP(appIP,UdpDataPort_ModemToApp,txpl,len+1);
}

90
modem/qo100modem.h Normal file
View File

@ -0,0 +1,90 @@
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <wchar.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/file.h>
#include <pthread.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <math.h>
#include <ifaddrs.h>
#include <zip.h>
#include "frameformat.h"
#include "main_helper.h"
#include "udp.h"
#define jpg_tempfilename "rxdata.jpg"
#define CRC16TX 0
#define CRC16RX 1
#define CRC16FILE 2
void stopModem();
uint8_t *unpack_data(uint8_t *rxd, int len);
void TX_Scramble(uint8_t *data, int len);
uint8_t *RX_Scramble(uint8_t *data, int len);
uint16_t Crc16_messagecalc(int rxtx, uint8_t *data,int len);
uint32_t crc32_messagecalc(int txrx, unsigned char *data, int len);
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();
void exit_fft();
uint8_t *convertQPSKSymToBytes(uint8_t *rxsymbols);
uint8_t *convert8PSKSymToBytes(uint8_t *rxsymbols, int len);
uint8_t *getPayload(uint8_t *rxb);
void showbytestring(char *title, uint8_t *data, int anz);
void init_packer();
void convertBytesToSyms_QPSK(uint8_t *bytes, uint8_t *syms, int bytenum);
void rotateQPSKsyms(uint8_t *src, uint8_t *dst, int len);
uint8_t * rotateBackQPSK(uint8_t *buf, int len, int rotations);
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);
extern int keeprunning;
extern int BC_sock_AppToModem;
extern int speed;
extern int speedmode;
extern int bitsPerSymbol;
extern int constellationSize;
/*
* Constellation as produced by the GR Constellation Decoder:
*
* 0 ... +1+1j
* 1 ... -1+1j
* 2 ... -1-1j
* 3 ... +1-1j
*
*
* */

209
modem/qpsk_rx.py Executable file
View File

@ -0,0 +1,209 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# SPDX-License-Identifier: GPL-3.0
#
# GNU Radio Python Flow Graph
# Title: QPSK RX-Modem
# Author: DJ0ABR
# Description: works with Gnu Radio 3.8.xxx
# 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 filter
from gnuradio.filter import firdes
from gnuradio import gr
import sys
import signal
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
class qpsk_rx(gr.top_block):
def __init__(self, resamp=5, samp_rate=44100):
gr.top_block.__init__(self, "QPSK RX-Modem")
##################################################
# Parameters
##################################################
self.resamp = resamp
self.samp_rate = samp_rate
##################################################
# Variables
##################################################
self.sps = sps = 4
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.mixf = mixf = 1500
##################################################
# Blocks
##################################################
self.mmse_resampler_xx_1 = filter.mmse_resampler_cc(0, resamp)
self.mmse_resampler_xx_0 = filter.mmse_resampler_ff(0, samp_rate / 8000)
self.low_pass_filter_0 = filter.fir_filter_fff(
1,
firdes.low_pass(
8,
samp_rate,
3500,
3100,
firdes.WIN_HAMMING,
6.76))
self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, 0.1, firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), 0.35, 11*sps*nfilts), nfilts, nfilts/2, 1.5, outputsps)
self.digital_lms_dd_equalizer_cc_0 = digital.lms_dd_equalizer_cc(15, 0.01, outputsps, qpsk__constellation)
self.digital_costas_loop_cc_0 = digital.costas_loop_cc(0.06, 4, False)
self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(qpsk__constellation)
self.blocks_udp_sink_0_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40137, 120, False)
self.blocks_udp_sink_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40136, 120, False)
self.blocks_udp_sink_0 = blocks.udp_sink(gr.sizeof_char*1, '127.0.0.1', 40135, 344, False)
self.blocks_multiply_xx_0_1_0 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_1 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_0_0 = blocks.multiply_vff(1)
self.blocks_interleave_0_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_interleave_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_float_to_int_0_1 = blocks.float_to_int(1, 1)
self.blocks_float_to_int_0_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_int_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
self.blocks_complex_to_float_1 = blocks.complex_to_float(1)
self.blocks_complex_to_float_0 = blocks.complex_to_float(1)
self.audio_source_0 = audio.source(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)
self.analog_const_source_x_0_1 = analog.sig_source_f(0, analog.GR_CONST_WAVE, 0, 0, 16777216)
self.analog_const_source_x_0_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_const_source_x_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_agc2_xx_0_0 = analog.agc2_cc(0.01, 0.2, 1, 1)
self.analog_agc2_xx_0_0.set_max_gain(3)
##################################################
# Connections
##################################################
self.connect((self.analog_agc2_xx_0_0, 0), (self.digital_costas_loop_cc_0, 0))
self.connect((self.analog_const_source_x_0, 0), (self.blocks_interleave_0, 0))
self.connect((self.analog_const_source_x_0_0, 0), (self.blocks_interleave_0_0, 0))
self.connect((self.analog_const_source_x_0_1, 0), (self.blocks_multiply_xx_0_1_0, 1))
self.connect((self.analog_sig_source_x_0_0_0, 0), (self.blocks_complex_to_float_1, 0))
self.connect((self.audio_source_0, 0), (self.low_pass_filter_0, 0))
self.connect((self.audio_source_0, 0), (self.mmse_resampler_xx_0, 0))
self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_float_to_int_0, 0))
self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_float_to_int_0_0, 0))
self.connect((self.blocks_complex_to_float_1, 1), (self.blocks_multiply_xx_0_0_0, 1))
self.connect((self.blocks_complex_to_float_1, 0), (self.blocks_multiply_xx_0_1, 1))
self.connect((self.blocks_float_to_complex_0, 0), (self.mmse_resampler_xx_1, 0))
self.connect((self.blocks_float_to_int_0, 0), (self.blocks_interleave_0_0, 1))
self.connect((self.blocks_float_to_int_0_0, 0), (self.blocks_interleave_0_0, 2))
self.connect((self.blocks_float_to_int_0_1, 0), (self.blocks_interleave_0, 1))
self.connect((self.blocks_interleave_0, 0), (self.blocks_udp_sink_0_0, 0))
self.connect((self.blocks_interleave_0_0, 0), (self.blocks_udp_sink_0_0_0, 0))
self.connect((self.blocks_multiply_xx_0_0_0, 0), (self.blocks_float_to_complex_0, 0))
self.connect((self.blocks_multiply_xx_0_1, 0), (self.blocks_float_to_complex_0, 1))
self.connect((self.blocks_multiply_xx_0_1_0, 0), (self.blocks_float_to_int_0_1, 0))
self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_udp_sink_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.blocks_complex_to_float_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.digital_constellation_decoder_cb_0, 0))
self.connect((self.digital_lms_dd_equalizer_cc_0, 0), (self.analog_agc2_xx_0_0, 0))
self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_lms_dd_equalizer_cc_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_0_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_1, 0))
self.connect((self.mmse_resampler_xx_0, 0), (self.blocks_multiply_xx_0_1_0, 0))
self.connect((self.mmse_resampler_xx_1, 0), (self.digital_pfb_clock_sync_xxx_0, 0))
def get_resamp(self):
return self.resamp
def set_resamp(self, resamp):
self.resamp = resamp
self.mmse_resampler_xx_1.set_resamp_ratio(self.resamp)
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)
self.low_pass_filter_0.set_taps(firdes.low_pass(8, self.samp_rate, 3500, 3100, firdes.WIN_HAMMING, 6.76))
self.mmse_resampler_xx_0.set_resamp_ratio(self.samp_rate / 8000)
def get_sps(self):
return self.sps
def set_sps(self, sps):
self.sps = sps
self.digital_pfb_clock_sync_xxx_0.update_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.0/float(self.sps), 0.35, 11*self.sps*self.nfilts))
def get_qpsk__constellation(self):
return self.qpsk__constellation
def set_qpsk__constellation(self, qpsk__constellation):
self.qpsk__constellation = qpsk__constellation
def get_outputsps(self):
return self.outputsps
def set_outputsps(self, outputsps):
self.outputsps = outputsps
def get_nfilts(self):
return self.nfilts
def set_nfilts(self, nfilts):
self.nfilts = nfilts
self.digital_pfb_clock_sync_xxx_0.update_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.0/float(self.sps), 0.35, 11*self.sps*self.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 = 'works with Gnu Radio 3.8.xxx'
parser = ArgumentParser(description=description)
parser.add_argument(
"-r", "--resamp", dest="resamp", type=intx, default=5,
help="Set resamp [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_rx, options=None):
if options is None:
options = argument_parser().parse_args()
tb = top_block_cls(resamp=options.resamp, 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()

140
modem/qpsk_tx.py Executable file
View File

@ -0,0 +1,140 @@
#!/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()

210
modem/rx_8psk.py Executable file
View File

@ -0,0 +1,210 @@
#!/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 filter
from gnuradio.filter import firdes
from gnuradio import gr
import sys
import signal
from argparse import ArgumentParser
from gnuradio.eng_arg import eng_float, intx
from gnuradio import eng_notation
class rx_8psk(gr.top_block):
def __init__(self, resamp=6, samp_rate=48000):
gr.top_block.__init__(self, "8PSK Modem DJ0ABR")
##################################################
# Parameters
##################################################
self.resamp = resamp
self.samp_rate = samp_rate
##################################################
# Variables
##################################################
self.sps = sps = 4
self.nfilts = nfilts = 32
self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.1/float(sps), 0.2, 11*sps*nfilts)
self.outputsps = outputsps = 7
self.mixf = mixf = 1500
##################################################
# Blocks
##################################################
self.mmse_resampler_xx_0_0 = filter.mmse_resampler_ff(0, samp_rate / 8000)
self.mmse_resampler_xx_0 = filter.mmse_resampler_cc(0, resamp)
self.low_pass_filter_0 = filter.fir_filter_fff(
1,
firdes.low_pass(
12,
samp_rate,
3900,
3300,
firdes.WIN_HAMMING,
6.76))
self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, 0.06, rrc_taps, nfilts, nfilts/16, 2, outputsps)
self.digital_lms_dd_equalizer_cc_0 = digital.lms_dd_equalizer_cc(15, 0.01, outputsps, digital.constellation_8psk_natural().base())
self.digital_diff_decoder_bb_0 = digital.diff_decoder_bb(8)
self.digital_costas_loop_cc_0 = digital.costas_loop_cc(0.15, 8, False)
self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(digital.constellation_8psk_natural().base())
self.blocks_udp_sink_0_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40137, 120, False)
self.blocks_udp_sink_0_0 = blocks.udp_sink(gr.sizeof_int*1, '127.0.0.1', 40136, 120, False)
self.blocks_udp_sink_0 = blocks.udp_sink(gr.sizeof_char*1, '127.0.0.1', 40135, 344, False)
self.blocks_multiply_xx_0_1_0 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_1 = blocks.multiply_vff(1)
self.blocks_multiply_xx_0_0_0 = blocks.multiply_vff(1)
self.blocks_interleave_0_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_interleave_0 = blocks.interleave(gr.sizeof_int*1, 1)
self.blocks_float_to_int_0_1 = blocks.float_to_int(1, 1)
self.blocks_float_to_int_0_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_int_0 = blocks.float_to_int(1, 16777216)
self.blocks_float_to_complex_0 = blocks.float_to_complex(1)
self.blocks_complex_to_float_1 = blocks.complex_to_float(1)
self.blocks_complex_to_float_0 = blocks.complex_to_float(1)
self.audio_source_0 = audio.source(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)
self.analog_const_source_x_0_1 = analog.sig_source_f(0, analog.GR_CONST_WAVE, 0, 0, 16777216)
self.analog_const_source_x_0_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_const_source_x_0 = analog.sig_source_i(0, analog.GR_CONST_WAVE, 0, 0, 1000)
self.analog_agc2_xx_0_0 = analog.agc2_cc(1e-2, 0.2, 1, 2)
self.analog_agc2_xx_0_0.set_max_gain(3)
##################################################
# Connections
##################################################
self.connect((self.analog_agc2_xx_0_0, 0), (self.digital_costas_loop_cc_0, 0))
self.connect((self.analog_const_source_x_0, 0), (self.blocks_interleave_0, 0))
self.connect((self.analog_const_source_x_0_0, 0), (self.blocks_interleave_0_0, 0))
self.connect((self.analog_const_source_x_0_1, 0), (self.blocks_multiply_xx_0_1_0, 1))
self.connect((self.analog_sig_source_x_0_0_0, 0), (self.blocks_complex_to_float_1, 0))
self.connect((self.audio_source_0, 0), (self.low_pass_filter_0, 0))
self.connect((self.audio_source_0, 0), (self.mmse_resampler_xx_0_0, 0))
self.connect((self.blocks_complex_to_float_0, 0), (self.blocks_float_to_int_0, 0))
self.connect((self.blocks_complex_to_float_0, 1), (self.blocks_float_to_int_0_0, 0))
self.connect((self.blocks_complex_to_float_1, 1), (self.blocks_multiply_xx_0_0_0, 1))
self.connect((self.blocks_complex_to_float_1, 0), (self.blocks_multiply_xx_0_1, 1))
self.connect((self.blocks_float_to_complex_0, 0), (self.mmse_resampler_xx_0, 0))
self.connect((self.blocks_float_to_int_0, 0), (self.blocks_interleave_0_0, 1))
self.connect((self.blocks_float_to_int_0_0, 0), (self.blocks_interleave_0_0, 2))
self.connect((self.blocks_float_to_int_0_1, 0), (self.blocks_interleave_0, 1))
self.connect((self.blocks_interleave_0, 0), (self.blocks_udp_sink_0_0, 0))
self.connect((self.blocks_interleave_0_0, 0), (self.blocks_udp_sink_0_0_0, 0))
self.connect((self.blocks_multiply_xx_0_0_0, 0), (self.blocks_float_to_complex_0, 0))
self.connect((self.blocks_multiply_xx_0_1, 0), (self.blocks_float_to_complex_0, 1))
self.connect((self.blocks_multiply_xx_0_1_0, 0), (self.blocks_float_to_int_0_1, 0))
self.connect((self.digital_constellation_decoder_cb_0, 0), (self.digital_diff_decoder_bb_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.blocks_complex_to_float_0, 0))
self.connect((self.digital_costas_loop_cc_0, 0), (self.digital_constellation_decoder_cb_0, 0))
self.connect((self.digital_diff_decoder_bb_0, 0), (self.blocks_udp_sink_0, 0))
self.connect((self.digital_lms_dd_equalizer_cc_0, 0), (self.analog_agc2_xx_0_0, 0))
self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_lms_dd_equalizer_cc_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_0_0, 0))
self.connect((self.low_pass_filter_0, 0), (self.blocks_multiply_xx_0_1, 0))
self.connect((self.mmse_resampler_xx_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0))
self.connect((self.mmse_resampler_xx_0_0, 0), (self.blocks_multiply_xx_0_1_0, 0))
def get_resamp(self):
return self.resamp
def set_resamp(self, resamp):
self.resamp = resamp
self.mmse_resampler_xx_0.set_resamp_ratio(self.resamp)
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)
self.low_pass_filter_0.set_taps(firdes.low_pass(12, self.samp_rate, 3900, 3300, firdes.WIN_HAMMING, 6.76))
self.mmse_resampler_xx_0_0.set_resamp_ratio(self.samp_rate / 8000)
def get_sps(self):
return self.sps
def set_sps(self, sps):
self.sps = sps
self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.1/float(self.sps), 0.2, 11*self.sps*self.nfilts))
def get_nfilts(self):
return self.nfilts
def set_nfilts(self, nfilts):
self.nfilts = nfilts
self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.nfilts, 1.1/float(self.sps), 0.2, 11*self.sps*self.nfilts))
def get_rrc_taps(self):
return self.rrc_taps
def set_rrc_taps(self, rrc_taps):
self.rrc_taps = rrc_taps
self.digital_pfb_clock_sync_xxx_0.update_taps(self.rrc_taps)
def get_outputsps(self):
return self.outputsps
def set_outputsps(self, outputsps):
self.outputsps = outputsps
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", "--resamp", dest="resamp", type=intx, default=6,
help="Set resamp [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=rx_8psk, options=None):
if options is None:
options = argument_parser().parse_args()
tb = top_block_cls(resamp=options.resamp, 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()

91
modem/scrambler.c Normal file
View File

@ -0,0 +1,91 @@
/*
* 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"
uint8_t scr[400] = {
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64,
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64,
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64,
130 , 239 , 223 , 19 , 146 , 254 , 12 , 86 , 106 , 68 ,
77 , 213 , 243 , 216 , 102 , 227 , 108 , 113 , 229 , 89 ,
26 , 64 , 138 , 216 , 225 , 121 , 194 , 137 , 152 , 64 ,
51 , 175 , 68 , 200 , 37 , 104 , 247 , 68 , 193 , 50 ,
19 , 14 , 196 , 81 , 4 , 236 , 191 , 249 , 83 , 25 ,
161 , 171 , 167 , 29 , 33 , 139 , 7 , 152 , 230 , 144 ,
125 , 206 , 34 , 236 , 112 , 78 , 219 , 34 , 181 , 161 ,
7 , 45 , 198 , 235 , 62 , 115 , 194 , 100 , 209 , 95 ,
186 , 161 , 53 , 10 , 110 , 246 , 122 , 246 , 207 , 194 ,
178 , 63 , 232 , 93 , 158 , 234 , 231 , 73 , 214 , 64
};
uint8_t rx_scrbuf[400];
void TX_Scramble(uint8_t *data, int len)
{
if (len > 400) return;
for(int i=0; i<len; i++)
data[i] ^= scr[i];
}
uint8_t *RX_Scramble(uint8_t *data, int len)
{
if (len > 400) return data;
memcpy(rx_scrbuf,data,len);
for(int i=0; i<len; i++)
rx_scrbuf[i] ^= scr[i];
return rx_scrbuf;
}

145
modem/tx_8psk.py Executable file
View File

@ -0,0 +1,145 @@
#!/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()

129
modem/udp.c Normal file
View File

@ -0,0 +1,129 @@
/*
* 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"
void *threadfunction(void *dummy);
#define MAXUDPTHREADS 20
RXCFG rxcfg[MAXUDPTHREADS];
int rxcfg_idx = 0;
// start UDP reception
// sock ... pointer to a socket (just a pointer to an int)
// port ... own port, messages only to this port are received
// rxfunc ... pointer to a callback function, will be called for received data
// keeprunning ... pointer to an int. If it is set to 0, the function exits
void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockaddr_in*), int *keeprunning)
{
if(rxcfg_idx >= MAXUDPTHREADS)
{
printf("max number of UDP threads\n");
exit(0);
}
rxcfg[rxcfg_idx].sock = sock;
rxcfg[rxcfg_idx].port = port;
rxcfg[rxcfg_idx].rxfunc = rxfunc;
rxcfg[rxcfg_idx].keeprunning = keeprunning;
// bind port
struct sockaddr_in sin;
*sock = socket(PF_INET, SOCK_DGRAM, 0);
if (*sock == -1){
printf("Failed to create Socket\n");
exit(0);
}
int enable = 1;
setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(*sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) != 0)
{
printf("Failed to bind socket, port:%d\n",port);
close(*sock);
exit(0);
}
// port sucessfully bound
// create the receive thread
pthread_t rxthread;
pthread_create(&rxthread, NULL, threadfunction, &(rxcfg[rxcfg_idx]));
rxcfg_idx++;
}
void *threadfunction(void *param)
{
RXCFG rxcfg;
memcpy((uint8_t *)(&rxcfg), (uint8_t *)param, sizeof(RXCFG));
socklen_t fromlen;
int recvlen;
char rxbuf[256];
struct sockaddr_in fromSock;
fromlen = sizeof(struct sockaddr_in);
while(*rxcfg.keeprunning)
{
recvlen = recvfrom(*rxcfg.sock, rxbuf, 256, 0, (struct sockaddr *)&fromSock, &fromlen);
if (recvlen > 0)
{
// data received, send it to callback function
(*rxcfg.rxfunc)((uint8_t *)rxbuf,recvlen, &fromSock);
}
}
return NULL;
}
// send UDP message
void sendUDP(char *destIP, int destPort, uint8_t *pdata, int len)
{
int sockfd;
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
printf("sendUDP: socket creation failed\n");
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(destPort);
//printf("Send to <%s><%d> Len:%d\n",destIP,destPort,len);
servaddr.sin_addr.s_addr=inet_addr(destIP);
sendto(sockfd, (char *)pdata, len, 0, (const struct sockaddr *) &servaddr, sizeof(servaddr));
close(sockfd);
}

9
modem/udp.h Normal file
View File

@ -0,0 +1,9 @@
void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockaddr_in*), int *keeprunning);
void sendUDP(char *destIP, int destPort, uint8_t *pdata, int len);
typedef struct {
int *sock;
int port;
void (*rxfunc)(uint8_t *, int, struct sockaddr_in*);
int *keeprunning;
} RXCFG;

View File

@ -0,0 +1,11 @@
{
"ExpandedNodes": [
"",
"\\oscardata",
"\\oscardata\\bin",
"\\oscardata\\obj",
"\\packages"
],
"SelectedNode": "\\packages",
"PreviewInSolutionExplorer": false
}

BIN
oscardata/.vs/oscardata/v15/.suo Executable file

Binary file not shown.

Binary file not shown.

BIN
oscardata/.vs/oscardata/v16/.suo Executable file

Binary file not shown.

Binary file not shown.

BIN
oscardata/.vs/slnx.sqlite Executable file

Binary file not shown.

25
oscardata/oscardata.sln Executable file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "oscardata", "oscardata\oscardata.csproj", "{989BF5C6-36F6-4158-9FB2-42E86D2020DB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{989BF5C6-36F6-4158-9FB2-42E86D2020DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{989BF5C6-36F6-4158-9FB2-42E86D2020DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{989BF5C6-36F6-4158-9FB2-42E86D2020DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{989BF5C6-36F6-4158-9FB2-42E86D2020DB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BCA5060C-33D6-4062-A3AF-6F304E7BFD89}
EndGlobalSection
EndGlobal

6
oscardata/oscardata/App.config Executable file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
</configuration>

204
oscardata/oscardata/ArraySend.cs Executable file
View File

@ -0,0 +1,204 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
// Input: Byte Array
// Action: sends this byte array to the modem
namespace oscardata
{
public static class ArraySend
{
static Timer TTimer;
static Byte[] txdata;
static int txlen;
public static int txpos;
static Byte txtype;
static bool sending = false;
public static Byte filestat = statics.noTX;
static private readonly object busyLock = new object();
static int timeout_period_ms = 10;
// start a timer which is used to send a file from txdata
public static void ArraySendInit()
{
TTimer = new Timer(new TimerCallback(TimerTick), 0, 0, timeout_period_ms);
}
static void setSending(bool v)
{
lock(busyLock)
{
sending = v;
if (v == false)
filestat = statics.LastFrame;
}
}
public static bool getSending()
{
bool v;
lock (busyLock)
{
v = sending;
}
return v;
}
/*
* start sending a file
* data ... contents of the file in a Byte array
* type ... type of the file (see statics)
* filename ... description of the file or its name (payload length max)
*/
public static bool Send(Byte[] data, Byte type, String filename, String RealFileName)
{
// check if already sending
if (getSending()) return false;
txtype = type;
txpos = 0;
filestat = statics.FirstFrame;
// add a file header and copy to txdata for transmission
AddHeader(data,filename, RealFileName);
// marker, we are sending
txlen = txdata.Length;
setSending(true);
return true;
}
public static void stopSending()
{
setSending(false);
}
static void AddHeader(Byte[] data, String filename, String realname)
{
long filesize = data.Length;// statics.GetFileSize(filename);
Byte[] fnarr = statics.StringToByteArray(realname);
Crc c = new Crc();
UInt16 fncrc = c.crc16_messagecalc(fnarr, fnarr.Length);
// create the file header
// 50 bytes ... Filename (or first 50 chars of the filename)
// 2 bytes .... CRC16 od the filename, this is used as a file ID
// 3 bytes .... size of file
Byte[] header = new Byte[55];
int len = fnarr.Length;
if (len > 50) len = 50;
Array.Copy(fnarr, header, len);
header[50] = (Byte)((fncrc >> 8)&0xff);
header[51] = (Byte)(fncrc&0xff);
header[52] = (Byte)((filesize >> 16) & 0xff);
header[53] = (Byte)((filesize >> 8) & 0xff);
header[54] = (Byte)(filesize & 0xff);
txdata = new Byte[data.Length + header.Length];
Array.Copy(header, txdata, header.Length);
Array.Copy(data, 0, txdata, header.Length, data.Length);
}
public static String rxFilename;
public static int FileID;
public static int FileSize;
public static Byte[] GetAndRemoveHeader(Byte[] data)
{
try
{
Byte[] fnarr = new byte[50];
Array.Copy(data, fnarr, 50);
rxFilename = statics.ByteArrayToString(fnarr);
FileID = data[50];
FileID <<= 8;
FileID += data[51];
FileSize = data[52];
FileSize <<= 8;
FileSize += data[53];
FileSize <<= 8;
FileSize += data[54];
Byte[] f = new byte[data.Length - 55];
Array.Copy(data, 55, f, 0, data.Length - 55);
return f;
}
catch { }
return null;
}
// runs every 10 ms
static void TimerTick(object stateInfo)
{
// check if we need to send something
if (getSending() == false) return; // nothing to send
// check the TX buffer, do not feed more data into
// the buffer if it has already more than 10 entries
if (Udp.GetBufferCount() > 3) return;
Byte[] txarr = new byte[statics.PayloadLen];
// check if txdata is smaller or equal one payload
if (filestat == statics.FirstFrame)
{
// send the first frame
if (txlen <= statics.PayloadLen)
{
// we just need to send one frame
txudp(txdata, txtype, statics.LastFrame);
setSending(false); // transmission complete
}
else
{
// additional frame follow
// from txdata send one chunk of length statics.PayloadLen
Array.Copy(txdata, 0, txarr, 0, statics.PayloadLen);
txudp(txarr, txtype, statics.FirstFrame);
txpos = statics.PayloadLen;
filestat = statics.NextFrame;
}
return;
}
if (filestat == statics.NextFrame)
{
// check if this is the last frame
int restlen = txlen - txpos;
if(restlen <= statics.PayloadLen)
{
// send as the last frame
Array.Copy(txdata, txpos, txarr, 0, restlen); // unused byte will be 0
txudp(txarr, txtype, statics.LastFrame);
txudp(txarr, txtype, statics.LastFrame);
setSending(false); // transmission complete
}
else
{
// additional frame follows
// from txdata send one chunk of length statics.PayloadLen
Array.Copy(txdata, txpos, txarr, 0, statics.PayloadLen);
txudp(txarr, txtype, statics.NextFrame);
txpos += statics.PayloadLen;
}
return;
}
}
static void txudp(Byte[] txdata, Byte txtype, Byte filestat)
{
// add the tytype and filestatus at the beginning
Byte[] darr = new byte[statics.PayloadLen + 2];
darr[0] = txtype;
darr[1] = filestat;
Array.Copy(txdata, 0, darr, 2, statics.PayloadLen);
Udp.UdpSend(darr);
// Console.WriteLine("TX filestat: " + filestat+ " data:" + darr[2].ToString("X2") + " " + darr[3].ToString("X2"));
}
}
}

700
oscardata/oscardata/Form1.Designer.cs generated Executable file
View File

@ -0,0 +1,700 @@
namespace oscardata
{
partial class Form1
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.timer_udpTX = new System.Windows.Forms.Timer(this.components);
this.timer_udprx = new System.Windows.Forms.Timer(this.components);
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.ts_ip = new System.Windows.Forms.ToolStripStatusLabel();
this.RXstatus = new System.Windows.Forms.ToolStripStatusLabel();
this.panel_constel = new System.Windows.Forms.Panel();
this.timer_qpsk = new System.Windows.Forms.Timer(this.components);
this.panel_txspectrum = new System.Windows.Forms.Panel();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.button_stopBERtest = new System.Windows.Forms.Button();
this.button_startBERtest = new System.Windows.Forms.Button();
this.rtb = new System.Windows.Forms.RichTextBox();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.groupBox1 = new System.Windows.Forms.Panel();
this.label_nextimage = new System.Windows.Forms.Label();
this.cb_loop = new System.Windows.Forms.CheckBox();
this.bt_rximages = new System.Windows.Forms.Button();
this.button_loadimage = new System.Windows.Forms.Button();
this.comboBox_quality = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.checkBox_big = new System.Windows.Forms.CheckBox();
this.button_cancelimg = new System.Windows.Forms.Button();
this.button_sendimage = new System.Windows.Forms.Button();
this.label_rximage = new System.Windows.Forms.Label();
this.label_tximage = new System.Windows.Forms.Label();
this.pictureBox_rximage = new System.Windows.Forms.PictureBox();
this.pictureBox_tximage = new System.Windows.Forms.PictureBox();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.button2 = new System.Windows.Forms.Button();
this.bt_openrxfile = new System.Windows.Forms.Button();
this.label_rxfile = new System.Windows.Forms.Label();
this.label_txfile = new System.Windows.Forms.Label();
this.rtb_RXfile = new System.Windows.Forms.RichTextBox();
this.rtb_TXfile = new System.Windows.Forms.RichTextBox();
this.bt_file_send = new System.Windows.Forms.Button();
this.bt_sendBinaryFile = new System.Windows.Forms.Button();
this.bt_file_html = new System.Windows.Forms.Button();
this.bt_file_ascii = new System.Windows.Forms.Button();
this.tabPage5 = new System.Windows.Forms.TabPage();
this.textBox1 = new System.Windows.Forms.TextBox();
this.bt_shutdown = new System.Windows.Forms.Button();
this.cb_savegoodfiles = new System.Windows.Forms.CheckBox();
this.cb_stampcall = new System.Windows.Forms.CheckBox();
this.tb_callsign = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.cb_speed = new System.Windows.Forms.ComboBox();
this.label_speed = new System.Windows.Forms.Label();
this.timer_searchmodem = new System.Windows.Forms.Timer(this.components);
this.statusStrip1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox_rximage)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox_tximage)).BeginInit();
this.tabControl1.SuspendLayout();
this.tabPage3.SuspendLayout();
this.tabPage5.SuspendLayout();
this.SuspendLayout();
//
// timer_udpTX
//
this.timer_udpTX.Tick += new System.EventHandler(this.timer1_Tick);
//
// timer_udprx
//
this.timer_udprx.Tick += new System.EventHandler(this.timer_udprx_Tick);
//
// statusStrip1
//
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripStatusLabel,
this.ts_ip,
this.RXstatus});
this.statusStrip1.Location = new System.Drawing.Point(0, 669);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(1304, 22);
this.statusStrip1.TabIndex = 4;
this.statusStrip1.Text = "statusStrip1";
//
// toolStripStatusLabel
//
this.toolStripStatusLabel.Name = "toolStripStatusLabel";
this.toolStripStatusLabel.Size = new System.Drawing.Size(39, 17);
this.toolStripStatusLabel.Text = "Status";
//
// ts_ip
//
this.ts_ip.Name = "ts_ip";
this.ts_ip.Size = new System.Drawing.Size(12, 17);
this.ts_ip.Text = "?";
//
// RXstatus
//
this.RXstatus.Name = "RXstatus";
this.RXstatus.Size = new System.Drawing.Size(58, 17);
this.RXstatus.Text = "RX-Status";
//
// panel_constel
//
this.panel_constel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(220)))));
this.panel_constel.Location = new System.Drawing.Point(11, 590);
this.panel_constel.Name = "panel_constel";
this.panel_constel.Size = new System.Drawing.Size(75, 75);
this.panel_constel.TabIndex = 5;
this.panel_constel.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_constel_Paint);
//
// timer_qpsk
//
this.timer_qpsk.Enabled = true;
this.timer_qpsk.Interval = 500;
this.timer_qpsk.Tick += new System.EventHandler(this.timer_qpsk_Tick);
//
// panel_txspectrum
//
this.panel_txspectrum.BackColor = System.Drawing.SystemColors.ControlLight;
this.panel_txspectrum.Location = new System.Drawing.Point(92, 590);
this.panel_txspectrum.Name = "panel_txspectrum";
this.panel_txspectrum.Size = new System.Drawing.Size(441, 76);
this.panel_txspectrum.TabIndex = 6;
this.panel_txspectrum.Paint += new System.Windows.Forms.PaintEventHandler(this.panel_txspectrum_Paint);
//
// tabPage1
//
this.tabPage1.Controls.Add(this.button_stopBERtest);
this.tabPage1.Controls.Add(this.button_startBERtest);
this.tabPage1.Controls.Add(this.rtb);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(1291, 553);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "BER Test";
this.tabPage1.UseVisualStyleBackColor = true;
//
// button_stopBERtest
//
this.button_stopBERtest.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button_stopBERtest.Location = new System.Drawing.Point(113, 13);
this.button_stopBERtest.Name = "button_stopBERtest";
this.button_stopBERtest.Size = new System.Drawing.Size(101, 32);
this.button_stopBERtest.TabIndex = 4;
this.button_stopBERtest.Text = "STOP";
this.button_stopBERtest.UseVisualStyleBackColor = true;
this.button_stopBERtest.Click += new System.EventHandler(this.button_stopBERtest_Click);
//
// button_startBERtest
//
this.button_startBERtest.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button_startBERtest.Location = new System.Drawing.Point(6, 13);
this.button_startBERtest.Name = "button_startBERtest";
this.button_startBERtest.Size = new System.Drawing.Size(101, 32);
this.button_startBERtest.TabIndex = 3;
this.button_startBERtest.Text = "START";
this.button_startBERtest.UseVisualStyleBackColor = true;
this.button_startBERtest.Click += new System.EventHandler(this.button_startBERtest_Click);
//
// rtb
//
this.rtb.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.rtb.Location = new System.Drawing.Point(6, 51);
this.rtb.Name = "rtb";
this.rtb.Size = new System.Drawing.Size(1270, 494);
this.rtb.TabIndex = 0;
this.rtb.Text = "";
//
// tabPage2
//
this.tabPage2.Controls.Add(this.groupBox1);
this.tabPage2.Controls.Add(this.label_rximage);
this.tabPage2.Controls.Add(this.label_tximage);
this.tabPage2.Controls.Add(this.pictureBox_rximage);
this.tabPage2.Controls.Add(this.pictureBox_tximage);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(1291, 553);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Image";
this.tabPage2.UseVisualStyleBackColor = true;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.label_nextimage);
this.groupBox1.Controls.Add(this.cb_loop);
this.groupBox1.Controls.Add(this.bt_rximages);
this.groupBox1.Controls.Add(this.button_loadimage);
this.groupBox1.Controls.Add(this.comboBox_quality);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Controls.Add(this.checkBox_big);
this.groupBox1.Controls.Add(this.button_cancelimg);
this.groupBox1.Controls.Add(this.button_sendimage);
this.groupBox1.Location = new System.Drawing.Point(3, 508);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(1277, 42);
this.groupBox1.TabIndex = 12;
//
// label_nextimage
//
this.label_nextimage.AutoSize = true;
this.label_nextimage.Location = new System.Drawing.Point(618, 19);
this.label_nextimage.Name = "label_nextimage";
this.label_nextimage.Size = new System.Drawing.Size(81, 13);
this.label_nextimage.TabIndex = 12;
this.label_nextimage.Text = "next image in ...";
//
// cb_loop
//
this.cb_loop.AutoSize = true;
this.cb_loop.Location = new System.Drawing.Point(621, 5);
this.cb_loop.Name = "cb_loop";
this.cb_loop.Size = new System.Drawing.Size(167, 17);
this.cb_loop.TabIndex = 11;
this.cb_loop.Text = "loop (send all images in folder)";
this.cb_loop.UseVisualStyleBackColor = true;
//
// bt_rximages
//
this.bt_rximages.Location = new System.Drawing.Point(534, 5);
this.bt_rximages.Name = "bt_rximages";
this.bt_rximages.Size = new System.Drawing.Size(75, 23);
this.bt_rximages.TabIndex = 10;
this.bt_rximages.Text = "RX Images";
this.bt_rximages.UseVisualStyleBackColor = true;
this.bt_rximages.Click += new System.EventHandler(this.bt_rximages_Click);
//
// button_loadimage
//
this.button_loadimage.Location = new System.Drawing.Point(265, 5);
this.button_loadimage.Name = "button_loadimage";
this.button_loadimage.Size = new System.Drawing.Size(75, 23);
this.button_loadimage.TabIndex = 0;
this.button_loadimage.Text = "Load Image";
this.button_loadimage.UseVisualStyleBackColor = true;
this.button_loadimage.Click += new System.EventHandler(this.button_loadimage_Click);
//
// comboBox_quality
//
this.comboBox_quality.FormattingEnabled = true;
this.comboBox_quality.Items.AddRange(new object[] {
"low, 30s",
"medium, 1min",
"high, 2min",
"very high, 4min"});
this.comboBox_quality.Location = new System.Drawing.Point(57, 7);
this.comboBox_quality.Name = "comboBox_quality";
this.comboBox_quality.Size = new System.Drawing.Size(109, 21);
this.comboBox_quality.TabIndex = 6;
this.comboBox_quality.Text = "medium, 1min";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(8, 10);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(42, 13);
this.label2.TabIndex = 7;
this.label2.Text = "Quality:";
//
// checkBox_big
//
this.checkBox_big.AutoSize = true;
this.checkBox_big.Checked = true;
this.checkBox_big.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBox_big.Location = new System.Drawing.Point(187, 9);
this.checkBox_big.Name = "checkBox_big";
this.checkBox_big.Size = new System.Drawing.Size(75, 17);
this.checkBox_big.TabIndex = 8;
this.checkBox_big.Text = "big picture";
this.checkBox_big.UseVisualStyleBackColor = true;
this.checkBox_big.CheckedChanged += new System.EventHandler(this.checkBox_small_CheckedChanged);
//
// button_cancelimg
//
this.button_cancelimg.Location = new System.Drawing.Point(443, 5);
this.button_cancelimg.Name = "button_cancelimg";
this.button_cancelimg.Size = new System.Drawing.Size(75, 23);
this.button_cancelimg.TabIndex = 9;
this.button_cancelimg.Text = "Cancel";
this.button_cancelimg.UseVisualStyleBackColor = true;
this.button_cancelimg.Click += new System.EventHandler(this.button_cancelimg_Click);
//
// button_sendimage
//
this.button_sendimage.Location = new System.Drawing.Point(346, 5);
this.button_sendimage.Name = "button_sendimage";
this.button_sendimage.Size = new System.Drawing.Size(75, 23);
this.button_sendimage.TabIndex = 1;
this.button_sendimage.Text = "Send Image";
this.button_sendimage.UseVisualStyleBackColor = true;
this.button_sendimage.Click += new System.EventHandler(this.button_sendimage_Click);
//
// label_rximage
//
this.label_rximage.AutoSize = true;
this.label_rximage.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label_rximage.Location = new System.Drawing.Point(648, 7);
this.label_rximage.Name = "label_rximage";
this.label_rximage.Size = new System.Drawing.Size(61, 13);
this.label_rximage.TabIndex = 5;
this.label_rximage.Text = "RX image";
//
// label_tximage
//
this.label_tximage.AutoSize = true;
this.label_tximage.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label_tximage.Location = new System.Drawing.Point(6, 7);
this.label_tximage.Name = "label_tximage";
this.label_tximage.Size = new System.Drawing.Size(60, 13);
this.label_tximage.TabIndex = 4;
this.label_tximage.Text = "TX image";
//
// pictureBox_rximage
//
this.pictureBox_rximage.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(250)))), ((int)(((byte)(240)))));
this.pictureBox_rximage.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.pictureBox_rximage.Location = new System.Drawing.Point(642, 27);
this.pictureBox_rximage.Name = "pictureBox_rximage";
this.pictureBox_rximage.Size = new System.Drawing.Size(640, 480);
this.pictureBox_rximage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox_rximage.TabIndex = 3;
this.pictureBox_rximage.TabStop = false;
//
// pictureBox_tximage
//
this.pictureBox_tximage.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(240)))));
this.pictureBox_tximage.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.pictureBox_tximage.Location = new System.Drawing.Point(1, 27);
this.pictureBox_tximage.Name = "pictureBox_tximage";
this.pictureBox_tximage.Size = new System.Drawing.Size(640, 480);
this.pictureBox_tximage.TabIndex = 2;
this.pictureBox_tximage.TabStop = false;
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Controls.Add(this.tabPage3);
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage5);
this.tabControl1.Location = new System.Drawing.Point(5, 3);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(1299, 579);
this.tabControl1.TabIndex = 3;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.button2);
this.tabPage3.Controls.Add(this.bt_openrxfile);
this.tabPage3.Controls.Add(this.label_rxfile);
this.tabPage3.Controls.Add(this.label_txfile);
this.tabPage3.Controls.Add(this.rtb_RXfile);
this.tabPage3.Controls.Add(this.rtb_TXfile);
this.tabPage3.Controls.Add(this.bt_file_send);
this.tabPage3.Controls.Add(this.bt_sendBinaryFile);
this.tabPage3.Controls.Add(this.bt_file_html);
this.tabPage3.Controls.Add(this.bt_file_ascii);
this.tabPage3.Location = new System.Drawing.Point(4, 22);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(1291, 553);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "File";
this.tabPage3.UseVisualStyleBackColor = true;
//
// button2
//
this.button2.Location = new System.Drawing.Point(17, 218);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(137, 23);
this.button2.TabIndex = 12;
this.button2.Text = "Cancel";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button_cancelimg_Click);
//
// bt_openrxfile
//
this.bt_openrxfile.Location = new System.Drawing.Point(17, 306);
this.bt_openrxfile.Name = "bt_openrxfile";
this.bt_openrxfile.Size = new System.Drawing.Size(137, 33);
this.bt_openrxfile.TabIndex = 11;
this.bt_openrxfile.Text = "Open RX file folder";
this.bt_openrxfile.UseVisualStyleBackColor = true;
this.bt_openrxfile.Click += new System.EventHandler(this.bt_openrxfile_Click);
//
// label_rxfile
//
this.label_rxfile.AutoSize = true;
this.label_rxfile.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label_rxfile.Location = new System.Drawing.Point(749, 10);
this.label_rxfile.Name = "label_rxfile";
this.label_rxfile.Size = new System.Drawing.Size(48, 13);
this.label_rxfile.TabIndex = 7;
this.label_rxfile.Text = "RX File";
//
// label_txfile
//
this.label_txfile.AutoSize = true;
this.label_txfile.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label_txfile.Location = new System.Drawing.Point(209, 10);
this.label_txfile.Name = "label_txfile";
this.label_txfile.Size = new System.Drawing.Size(47, 13);
this.label_txfile.TabIndex = 6;
this.label_txfile.Text = "TX File";
//
// rtb_RXfile
//
this.rtb_RXfile.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.rtb_RXfile.Location = new System.Drawing.Point(736, 31);
this.rtb_RXfile.Name = "rtb_RXfile";
this.rtb_RXfile.Size = new System.Drawing.Size(526, 508);
this.rtb_RXfile.TabIndex = 5;
this.rtb_RXfile.Text = "";
//
// rtb_TXfile
//
this.rtb_TXfile.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.rtb_TXfile.Location = new System.Drawing.Point(204, 31);
this.rtb_TXfile.Name = "rtb_TXfile";
this.rtb_TXfile.Size = new System.Drawing.Size(526, 508);
this.rtb_TXfile.TabIndex = 4;
this.rtb_TXfile.Text = "";
//
// bt_file_send
//
this.bt_file_send.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.bt_file_send.ForeColor = System.Drawing.Color.Red;
this.bt_file_send.Location = new System.Drawing.Point(17, 157);
this.bt_file_send.Name = "bt_file_send";
this.bt_file_send.Size = new System.Drawing.Size(137, 37);
this.bt_file_send.TabIndex = 3;
this.bt_file_send.Text = "SEND";
this.bt_file_send.UseVisualStyleBackColor = true;
this.bt_file_send.Click += new System.EventHandler(this.bt_file_send_Click);
//
// bt_sendBinaryFile
//
this.bt_sendBinaryFile.Location = new System.Drawing.Point(17, 89);
this.bt_sendBinaryFile.Name = "bt_sendBinaryFile";
this.bt_sendBinaryFile.Size = new System.Drawing.Size(137, 23);
this.bt_sendBinaryFile.TabIndex = 2;
this.bt_sendBinaryFile.Text = "Load Binary File";
this.bt_sendBinaryFile.UseVisualStyleBackColor = true;
this.bt_sendBinaryFile.Click += new System.EventHandler(this.bt_sendBinaryFile_Click);
//
// bt_file_html
//
this.bt_file_html.Location = new System.Drawing.Point(17, 60);
this.bt_file_html.Name = "bt_file_html";
this.bt_file_html.Size = new System.Drawing.Size(137, 23);
this.bt_file_html.TabIndex = 1;
this.bt_file_html.Text = "Load HTML File";
this.bt_file_html.UseVisualStyleBackColor = true;
this.bt_file_html.Click += new System.EventHandler(this.button2_Click);
//
// bt_file_ascii
//
this.bt_file_ascii.Location = new System.Drawing.Point(17, 31);
this.bt_file_ascii.Name = "bt_file_ascii";
this.bt_file_ascii.Size = new System.Drawing.Size(137, 23);
this.bt_file_ascii.TabIndex = 0;
this.bt_file_ascii.Text = "Load ASCII Text File";
this.bt_file_ascii.UseVisualStyleBackColor = true;
this.bt_file_ascii.Click += new System.EventHandler(this.bt_file_ascii_Click);
//
// tabPage5
//
this.tabPage5.Controls.Add(this.textBox1);
this.tabPage5.Controls.Add(this.bt_shutdown);
this.tabPage5.Controls.Add(this.cb_savegoodfiles);
this.tabPage5.Controls.Add(this.cb_stampcall);
this.tabPage5.Controls.Add(this.tb_callsign);
this.tabPage5.Controls.Add(this.label1);
this.tabPage5.Location = new System.Drawing.Point(4, 22);
this.tabPage5.Name = "tabPage5";
this.tabPage5.Size = new System.Drawing.Size(1291, 553);
this.tabPage5.TabIndex = 4;
this.tabPage5.Text = "Setup";
this.tabPage5.UseVisualStyleBackColor = true;
//
// textBox1
//
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.textBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.textBox1.ForeColor = System.Drawing.Color.Red;
this.textBox1.Location = new System.Drawing.Point(379, 78);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(259, 55);
this.textBox1.TabIndex = 5;
this.textBox1.Text = "before switching off the modem SBC\r\nclick here to avoid defective SD-cards.\r\nWAIT" +
" 1 minute before powering OFF the modem.";
//
// bt_shutdown
//
this.bt_shutdown.Location = new System.Drawing.Point(379, 49);
this.bt_shutdown.Name = "bt_shutdown";
this.bt_shutdown.Size = new System.Drawing.Size(155, 23);
this.bt_shutdown.TabIndex = 4;
this.bt_shutdown.Text = "Shutdown Modem-SBC";
this.bt_shutdown.UseVisualStyleBackColor = true;
this.bt_shutdown.Click += new System.EventHandler(this.bt_shutdown_Click);
//
// cb_savegoodfiles
//
this.cb_savegoodfiles.AutoSize = true;
this.cb_savegoodfiles.Checked = true;
this.cb_savegoodfiles.CheckState = System.Windows.Forms.CheckState.Checked;
this.cb_savegoodfiles.Location = new System.Drawing.Point(106, 136);
this.cb_savegoodfiles.Name = "cb_savegoodfiles";
this.cb_savegoodfiles.Size = new System.Drawing.Size(159, 17);
this.cb_savegoodfiles.TabIndex = 3;
this.cb_savegoodfiles.Text = "Save good files/images only";
this.cb_savegoodfiles.UseVisualStyleBackColor = true;
//
// cb_stampcall
//
this.cb_stampcall.AutoSize = true;
this.cb_stampcall.Checked = true;
this.cb_stampcall.CheckState = System.Windows.Forms.CheckState.Checked;
this.cb_stampcall.Location = new System.Drawing.Point(106, 113);
this.cb_stampcall.Name = "cb_stampcall";
this.cb_stampcall.Size = new System.Drawing.Size(146, 17);
this.cb_stampcall.TabIndex = 2;
this.cb_stampcall.Text = "Insert Callsign into picture";
this.cb_stampcall.UseVisualStyleBackColor = true;
//
// tb_callsign
//
this.tb_callsign.CharacterCasing = System.Windows.Forms.CharacterCasing.Upper;
this.tb_callsign.Location = new System.Drawing.Point(106, 49);
this.tb_callsign.Name = "tb_callsign";
this.tb_callsign.Size = new System.Drawing.Size(151, 20);
this.tb_callsign.TabIndex = 1;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(49, 52);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(46, 13);
this.label1.TabIndex = 0;
this.label1.Text = "Callsign:";
//
// cb_speed
//
this.cb_speed.FormattingEnabled = true;
this.cb_speed.Items.AddRange(new object[] {
"3000 QPSK BW: 1800 Hz ",
"3150 QPSK BW: 1900 Hz ",
"3675 QPSK BW: 2200 Hz ",
"4000 QPSK BW: 2400 Hz ",
"4410 QPSK BW: 2700 Hz (default QO-100)",
"4800 QPSK BW: 2900 Hz (experimental)",
"5500 8PSK BW: 2300 Hz",
"6000 8PSK BW: 2500 Hz (QO-100 beacon)"});
this.cb_speed.Location = new System.Drawing.Point(636, 644);
this.cb_speed.Name = "cb_speed";
this.cb_speed.Size = new System.Drawing.Size(324, 21);
this.cb_speed.TabIndex = 11;
this.cb_speed.Text = "4410 QPSK BW: 2700 Hz (default QO-100)";
this.cb_speed.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
//
// label_speed
//
this.label_speed.AutoSize = true;
this.label_speed.Location = new System.Drawing.Point(545, 647);
this.label_speed.Name = "label_speed";
this.label_speed.Size = new System.Drawing.Size(71, 13);
this.label_speed.TabIndex = 12;
this.label_speed.Text = "Speed [bit/s]:";
//
// timer_searchmodem
//
this.timer_searchmodem.Interval = 1000;
this.timer_searchmodem.Tick += new System.EventHandler(this.timer_searchmodem_Tick);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1304, 691);
this.Controls.Add(this.cb_speed);
this.Controls.Add(this.label_speed);
this.Controls.Add(this.panel_txspectrum);
this.Controls.Add(this.panel_constel);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.tabControl1);
this.ForeColor = System.Drawing.SystemColors.ControlText;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "Form1";
this.Text = "QO-100 NB Transponder HS Transmission AMSAT-DL V0.1 by DJ0ABR";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false);
this.tabPage2.PerformLayout();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBox_rximage)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox_tximage)).EndInit();
this.tabControl1.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.tabPage3.PerformLayout();
this.tabPage5.ResumeLayout(false);
this.tabPage5.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Timer timer_udpTX;
private System.Windows.Forms.Timer timer_udprx;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel;
private System.Windows.Forms.Panel panel_constel;
private System.Windows.Forms.Timer timer_qpsk;
private System.Windows.Forms.Panel panel_txspectrum;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.Button button_stopBERtest;
private System.Windows.Forms.Button button_startBERtest;
private System.Windows.Forms.RichTextBox rtb;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.ComboBox comboBox_quality;
private System.Windows.Forms.Button button_loadimage;
private System.Windows.Forms.Button button_cancelimg;
private System.Windows.Forms.Button button_sendimage;
private System.Windows.Forms.CheckBox checkBox_big;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label_rximage;
private System.Windows.Forms.Label label_tximage;
private System.Windows.Forms.PictureBox pictureBox_rximage;
private System.Windows.Forms.PictureBox pictureBox_tximage;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.ToolStripStatusLabel ts_ip;
private System.Windows.Forms.Panel groupBox1;
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.RichTextBox rtb_TXfile;
private System.Windows.Forms.Button bt_file_send;
private System.Windows.Forms.Button bt_sendBinaryFile;
private System.Windows.Forms.Button bt_file_html;
private System.Windows.Forms.Button bt_file_ascii;
private System.Windows.Forms.RichTextBox rtb_RXfile;
private System.Windows.Forms.Label label_rxfile;
private System.Windows.Forms.Label label_txfile;
private System.Windows.Forms.ToolStripStatusLabel RXstatus;
private System.Windows.Forms.ComboBox cb_speed;
private System.Windows.Forms.Label label_speed;
private System.Windows.Forms.Timer timer_searchmodem;
private System.Windows.Forms.Button bt_rximages;
private System.Windows.Forms.Button bt_openrxfile;
private System.Windows.Forms.CheckBox cb_loop;
private System.Windows.Forms.Label label_nextimage;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TabPage tabPage5;
private System.Windows.Forms.TextBox tb_callsign;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.CheckBox cb_stampcall;
private System.Windows.Forms.CheckBox cb_savegoodfiles;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button bt_shutdown;
}
}

1330
oscardata/oscardata/Form1.cs Executable file

File diff suppressed because it is too large Load Diff

212
oscardata/oscardata/Form1.resx Executable file
View File

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="timer_udpTX.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="timer_udprx.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>138, 17</value>
</metadata>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>255, 17</value>
</metadata>
<metadata name="timer_qpsk.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>371, 17</value>
</metadata>
<metadata name="timer_searchmodem.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>482, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD/gIAC5ZhVV+eZVbLmmVXL5plVwOWYVZ/lmVWK5ZhVV/+AgAIAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA6JtVIeaZVc/mmFWu55dVNgAAAAAAAAAAAAAAAAAAAADjl1Ub5ZhUT+iX
URYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOeXWCDnmVXl5ppUW9+fYAjmmVZu5ZhVx+aZVcDmmVWl55pUiOea
VWD/gEAE6KJdC/+AQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gIAC55lV0eWYVlninVga5plVz+aaVJfjl1UbAAAAAAAA
AAAAAAAA1apVBueaVzXVqlUGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaaVlPmmlWr359gCOaZVc7mmlZl359QEOaZ
Vo/mmVXe5plVwOaZVYTmmFY+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF43
NXheNzb/XTY2dgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5ppVteiXVyznmVZr5plWmN+f
UBDmmVXU55lVqOiXURYAAAAAAAAAAAAAAAAAAAAAAAAAAICAgAR6enqjAAAAAAAAAAAAAAAAAAAAAAAA
AABdNjZ2Xjc2/143Nv9eNzb/XTY2dgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlmFXHAAAAAOaa
VcninVga55pWkueZVagAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgIAEhISEvnNzc+cAAAAAAAAAAAAA
AAAAAAAAXTY2dl43Nv9eNzb/Xjc2/143Nv9eNzb/XTY2dgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaa
VbUAAAAA5plVwwAAAADmmVXd6JdRFgAAAABdXV2kXV1dNAAAAAAAAAAAgICAAoqKisCQkJD/a2trvQAA
AAAAAAAAAAAAAF02NnZeNzb/Xjc2/143Nv9eNzb/Xjc2/143Nv9eNzb/XTY2dgAAAAAAAAAAAAAAAAAA
AAAAAAAA5ZhWlQAAAADlmFSpAAAAAOaZVcEAAAAAAAAAAFxcXDpeXl64XV1dfl9fX2aOjo7NoaGh/4qK
ivxoaGhRAAAAAAAAAAAAAAAAXjc2/3ZJSP94S0n/ekxL/3tNTP99T03/flBO/4BRUP9FMDD/Oy0ttQAA
AAAAAAAAAAAAAAAAAADnmVR/AAAAAOaaVY0AAAAA5plUhQAAAAAAAAAAAAAAAF9fX4EAAAAAkJCQ1rGx
sf+rq6v/cXFxxj4+PiFhYWHXcHBwywAAAABfODaJZTw7/21CQf9uQ0L/cEVD/3FGRf9zR0b/VTs6/ykp
Kf9CMC//XTY2dgAAAAAAAAAAAAAAAOWYVk3tklsO5ppVXdWqVQbmm1Q9AAAAAAAAAAAAAAAAX19fWZ+f
n9m/v7//wcHB/4GBgfFOTk5LT09P77CwsP9xcXH/b29vywAAAABfODaJYDg3/2M7Ov9kPDv/Zj08/0w1
NP8pKSn/Qi8v/143Nv9eNzb/XTY2dgAAAAAAAAAA/4CAAueaVT//gEAE6JtXOAAAAAAAAAAAAAAAAAAA
AACoqKjCz8/P/9TU1P+VlZX/T09P/0JCQvrS0tL/rq6u/46Ojv9xcXH/b29vywAAAABfODaJXjc2/143
Nv9FMTD/KSkp/0IvL/9eNzb/Xjc2/143Nv9eNzb/XTY2dgAAAAAAAAAA7ZJbDv+AQATfn2AIAAAAAAAA
AAAAAAAApaWlvtfX1//k5OT/oaGh8ZmZmf9qamr+2dnZ/7m5uf/AwMD/qamp/46Ojv9xcXH/b29vywAA
AABfODaJRTEw/ykpKf9CLy//Xjc2/143Nv9eNzb/Xjc2/143Nv9eNzb/XTY2dgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAKamprTLy8v/zMzM9qysrJ1paWlEbGxs++Li4v/z8/P/3t7e/6urq//AwMD/qamp/46O
jv9xcXH/b29vyykpKXYpKSn/Qi8v/3ZJSP94S0n/ekxL/3tNTP99T03/flBO/4BRUP9eNzb/AAAAAAAA
AAAAAAAAAAAAAAAAAACsrKyfuLi427i4uJabm5spdXV1GICAgOzo6Oj///////n5+f/v7+//3t7e/6ur
q//AwMD/qqqq/46Ojv9xcXH/YGBg/ykpKYlfODaJZTw7/21CQf9uQ0L/cEVD/3FGRf9zR0b/akA//143
N4cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOjo7L29vb/8nJyf/7+/v///////n5
+f/v7+//3t7e/6urq//AwMD/qqqq/4+Pj/9ycnL/b29vygAAAABfODaJYDg3/2M7Ov9kPDv/Zj08/2M7
Ov9fODaJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJeXl5qsrKz/1NTU/8XF
xf/7+/v///////n5+f/v7+//3t7e/6ysrP/AwMD/qqqq/4+Pj/9ycnL/b29vygAAAABfODaJXjc2/143
Nv9eNzb/Xzg2iQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIKC
go2srKz/1NTU/8XFxf/7+/v///////n5+f/v7+//3t7e/6ysrP/AwMD/qqqq/4+Pj/9ycnL/b29vygAA
AABfODaJXjc2/184NokAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXjc1eF43
Nv9dNjZ2AAAAAIKCgo2srKz/1NTU/8XFxf/7+/v///////n5+f/v7+//3t7e/6ysrP/AwMD/qqqq/4+P
j/92dnbzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF02
NnZeNzb/Xjc2/143Nv9dNjZ2AAAAAIKCgo2srKz/1NTU/8XFxf/7+/v///////n5+f/v7+//3t7e/6ys
rP/AwMD/oKCg/4iIiIUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABdNjZ2Xjc2/143Nv9eNzb/Xjc2/143Nv9dNjZ2AAAAAIKCgo2srKz/1NTU/8XFxf/7+/v///////n5
+f/v7+//3t7e/6enp/+Pj4/NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAXTY2dl43Nv9eNzb/Xjc2/143Nv9eNzb/Xjc2/143Nv9dNjZ2KSkpdltbW/+srKz/1NTU/8XF
xf/7+/v///////n5+f/p6en/lJSU6ElJST9RUVFCa2trjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABeNzb/dklI/3hLSf96TEv/e01M/31PTf9+UE7/gFFQ/0UxMP8pKSn/KSkpiYKC
go2srKz/1NTU/8XFxf/7+/v/9PT0/52dnelycnL1Nzc357CwsPCJiYn8YmJingAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84NollPDv/bUJB/25DQv9wRUP/cUZF/3NHRv9VOzr/KSkp/0Iv
L/9dNjZ2AAAAAIKCgo2srKz/1NTU/7y8vP+ioqLLc3NzWaCgoPS4uLjz1dXV/6urq/97e3v+Y2NjoAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84NolgODf/Yzs6/2Q8O/9mPTz/TDU0/ykp
Kf9CLy//Xjc2/143Nv9dNjZ2AAAAAIGBgY6ZmZnmnZ2dgAAAAACCgoI9xsbG9Pz8/P/r6+v/uLi4/6qq
qv96enr+Y2NjoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84NoleNzb/Xjc2/0Ux
MP8pKSn/Qi8v/143Nv9eNzb/Xjc2/143Nv9dNjZ2AAAAAAAAAAAAAAAAAAAAAIyMjHzT09P/29vb//r6
+v/r6+v/t7e3/6ioqP94eHj+YmJioQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84
NolFMTD/KSkp/0IvL/9eNzb/Xjc2/143Nv9eNzb/Xjc2/143Nv9dNjZ2AAAAAAAAAAAAAAAAAAAAAIKC
gonOzs7/29vb//r6+v/r6+v/tra2/6enp/92dnb+Y2NjoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADsuLchCLy//dklI/3hLSf96TEv/e01M/31PTf9+UE7/gFFQ/143Nv8AAAAAAAAAAAAA
AAAAAAAAAAAAAIKCgoPOzs7/29vb//r6+v/r6+v/tra2/6enp/91dXX+aGhomwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84NollPDv/bUJB/25DQv9wRUP/cUZF/3NHRv9qQD//Xjc3hwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAISEhHbOzs7/29vb//r6+v/r6+v/tra2/6ampv94eHjoAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84NolgODf/Yzs6/2Q8O/9mPTz/Yzs6/184
NokAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAISEhHbOzs7/29vb//r6+v/r6+v/np6e/3Z2
dn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84NoleNzb/Xjc2/143
Nv9fODaJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAISEhHTOzs7/29vb/8HB
wf+Dg4P+WVlZLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF84
NoleNzb/Xzg2iQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAISE
hHS0tLTZh4eHhqysrDEAAAAA4A///8PH//+AA///Acf//wAf+P8A+fB/Q/HgP1JhwB9WAcAPV0BABwcA
IAMPABABjgAIAPwAAAD4AAAA/4ABAf+AAIP/wABH/iAAf/wQAH/4CAD/8AAAP/AAAB/wAQAP+ACIB/wA
eAP+ADwB/wA+AP+APwD/wH+A/+D/wP/x/+E=
</value>
</data>
</root>

19
oscardata/oscardata/Program.cs Executable file
View File

@ -0,0 +1,19 @@
using System;
using System.Windows.Forms;
namespace oscardata
{
static class Program
{
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("oscardata")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("oscardata")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("989bf5c6-36f6-4158-9fb2-42e86d2020db")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace oscardata.Properties {
using System;
/// <summary>
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
/// </summary>
// Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
// -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
// mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("oscardata.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap constelBG {
get {
object obj = ResourceManager.GetObject("constelBG", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap defaultpic {
get {
object obj = ResourceManager.GetObject("defaultpic", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap Satellite_icon {
get {
object obj = ResourceManager.GetObject("Satellite_icon", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="defaultpic" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>defaultpic.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Satellite_icon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Satellite-icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="constelBG" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>constelBG.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace oscardata.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
</configuration>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Some files were not shown because too many files have changed in this diff Show More