pull/19/head
Jean-Michel Friedt 2024-06-07 11:31:05 +02:00
parent 6f8451c901
commit fbed8ca129
7 changed files with 297 additions and 172 deletions

View File

@ -36,44 +36,11 @@ to solve any issue related to ``ImportError: libgnuradio-m17.so.1.0.0: cannot op
When running the flowgraph found in ``examples`` with ``gnuradio-companion ../examples/m17_streamer.grc``
<img src="examples/m17_streamer.png">
<img src="examples/m17_loopback.png">
the output should be
See <a href="examples/README.md">examples/README.md</a> for the expected output and unit testing examples.
```
Generating: '.../M17_Implementations/SP5WWP/gr-m17/examples/m17_streamer.py'
Executing: /usr/bin/python3 -u .../M17_Implementations/SP5WWP/gr-m17/examples/m17_streamer.py
new meta: helloworld
new SRC ID: 1 2 3 4 5 6
new DST ID: 255 255 255 255 255 255
New sampling rate: 8800.000000
new type: 0 0
got_lsf=1
LSF
DST: #BCAST SRC: FPR-4U3F TYPE: 0000 META: 68656C6C6F776F726C6400000000 LSF_CRC_OK
FN: 0000 PLD: 00000000000000000000000000000000
FN: 0001 PLD: 00000000000000000000000000000000
FN: 0002 PLD: 00000000000000000000000000000000
FN: 0003 PLD: 00000000000000000000000000000000
FN: 0004 PLD: 00000000000000000000000000000000
DST: #BCAST SRC: FPR-4U3F TYPE: 0000 META: 68656C6C6F776F726C6400000000 LSF_CRC_OK
FN: 0005 PLD: 00000000000000000000000000000000
FN: 0006 PLD: 00000000000000000000000000000000
FN: 0007 PLD: 00000000000000000000000000000000
FN: 0008 PLD: 00000000000000000000000000000000
FN: 0009 PLD: 00000000000000000000000000000000
FN: 000A PLD: 00000000000000000000000000000000
DST: #BCAST SRC: FPR-4U3F TYPE: 0000 META: 68656C6C6F776F726C6400000000 LSF_CRC_OK
FN: 000B PLD: 00000000000000000000000000000000
FN: 000C PLD: 00000000000000000000000000000000
FN: 000D PLD: 00000000000000000000000000000000
FN: 000E PLD: 00000000000000000000000000000000
FN: 000F PLD: 00000000000000000000000000000000
```
Notice that due to the verbose output of gr-m17 and the slow console of GNU Radio Companion, I
Notice that due to the verbose output of ``gr-m17`` and the slow console of GNU Radio Companion, I
would strongly advise generating the Python script from GNU Radio Companion and then execute
``python3 m17_streamer.py`` from a terminal to avoid waiting for a long time for GNU Radio
Companion to flush all messages.

View File

@ -2,6 +2,8 @@
### m17_rx.grc
<img src="m17_rx.png">
This receiver testing example relies on ``../M17_Implementations/SP5WWP/m17-coder/m17-coder-sym``
to broadcast a signal. Following this unit testing example, run this flowchart along with
```
@ -26,17 +28,56 @@ DST: ALL SRC: AB1CDE TYPE: 0005 META: 0000000000000000000000000000 LSF_
It would be wise to execute from a terminal rather than the GNU Radio Companion graphical interface
to avoid flooding the console.
### m17_tx.grc
<img src="m17_tx.png">
This transmitter testing example relies on ``../M17_Implementations/SP5WWP/m17-decoder/m17-decoder-sym``
to decode a signal. Following this unit testing example, run this flowchart along with
```
mkfifo /tmp/fifo1
mkfifo /tmp/fifo2
../M17_Implementations/SP5WWP/m17-decoder/m17-decoder-sym < /tmp/fifo2
```
and the output of ``python3 ./m17_tx.py`` should be
```
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
FN: 0018 PLD: 01020304050600000000000000000000 e=0.0
FN: 0019 PLD: 01020304050600000000000000000000 e=0.0
FN: 001A PLD: 01020304050600000000000000000000 e=0.0
FN: 001B PLD: 01020304050600000000000000000000 e=0.0
FN: 001C PLD: 01020304050600000000000000000000 e=0.0
FN: 001D PLD: 01020304050600000000000000000000 e=0.0
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
FN: 001E PLD: 01020304050600000000000000000000 e=0.0
```
### m17_streamer.grc
Loopback demo with TX and RX both in GNU Radio.
<img src="m17_loopback.png">
The output should be
```
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
DST: AB2CDE SRC: AB1CDE TYPE: 0005 META: 48656C6C6F210000000000000000 LSF_CRC_OK
```
## TO BE DEBUGGED AND VALIDATED
### transmitterPLUTOSDR.grc
M17 transmitter with ADALM Pluto SDR.
### receiverRTLSDR.grc
M17 receiver with RTL SDR. Automatic Frequency Correction can be enabled as an option.
### m17_streamer.grc
Old loopback demo.
<img src="m17_loopback.png">
### m17_loopback_noisychannel.grc
Loopback demo with the addition of noise, no modulation/no channnel.

BIN
examples/m17_rx.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

215
examples/m17_tx.grc 100644
View File

@ -0,0 +1,215 @@
options:
parameters:
author: Wojciech SP5WWP
catch_exceptions: 'True'
category: '[GRC Hier Blocks]'
cmake_opt: ''
comment: ''
copyright: M17 Project, Jan 2024
description: ''
gen_cmake: 'On'
gen_linking: dynamic
generate_options: qt_gui
hier_block_src_path: '.:'
id: m17_tx
max_nouts: '0'
output_language: python
placement: (0,0)
qt_qss_theme: ''
realtime_scheduling: ''
run: 'True'
run_command: '{python} -u {filename}'
run_options: prompt
sizing_mode: fixed
thread_safe_setters: ''
title: M17 loopback demo
window_size: (1000,1000)
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [8, 4.0]
rotation: 0
state: enabled
blocks:
- name: dst_str
id: variable_qtgui_entry
parameters:
comment: ''
entry_signal: editingFinished
gui_hint: ''
label: DST
type: string
value: AB2CDE
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [568, 12.0]
rotation: 0
state: true
- name: meta_str
id: variable_qtgui_entry
parameters:
comment: ''
entry_signal: editingFinished
gui_hint: ''
label: META
type: string
value: Hello!
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [288, 12.0]
rotation: 0
state: true
- name: samp_rate
id: variable
parameters:
comment: ''
value: '4800'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [192, 12.0]
rotation: 0
state: true
- name: src_str
id: variable_qtgui_entry
parameters:
comment: ''
entry_signal: editingFinished
gui_hint: ''
label: SRC
type: string
value: AB1CDE
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [424, 12.0]
rotation: 0
state: true
- name: type_val
id: variable_qtgui_entry
parameters:
comment: ''
entry_signal: editingFinished
gui_hint: ''
label: TYPE
type: int
value: '5'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [712, 12.0]
rotation: 0
state: true
- name: blocks_file_sink_0
id: blocks_file_sink
parameters:
affinity: ''
alias: ''
append: 'False'
comment: '/tmp/fifo2 was created with
mkfifo /tmp/fifo2'
file: /tmp/fifo2
type: float
unbuffered: 'False'
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [752, 144.0]
rotation: 0
state: enabled
- name: blocks_throttle2_0
id: blocks_throttle2
parameters:
affinity: ''
alias: ''
comment: ''
ignoretag: 'True'
limit: auto
maximum: '0.1'
maxoutbuf: '0'
minoutbuf: '0'
samples_per_second: samp_rate
type: float
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [536, 152.0]
rotation: 0
state: true
- name: blocks_vector_source_x_0_2
id: blocks_vector_source_x
parameters:
affinity: ''
alias: ''
comment: ''
maxoutbuf: '0'
minoutbuf: '0'
repeat: 'True'
tags: '[]'
type: byte
vector: (0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00)
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [16, 144.0]
rotation: 0
state: true
- name: m17_m17_coder_0
id: m17_m17_coder
parameters:
affinity: ''
alias: ''
comment: ''
debug: 'False'
dst_id: dst_str
maxoutbuf: '0'
meta: meta_str
minoutbuf: '0'
src_id: src_str
type: type_val
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [320, 128.0]
rotation: 0
state: true
- name: note_0_2
id: note
parameters:
alias: ''
comment: ''
note: DATA
states:
bus_sink: false
bus_source: false
bus_structure: null
coordinate: [200, 88.0]
rotation: 0
state: true
connections:
- [blocks_throttle2_0, '0', blocks_file_sink_0, '0']
- [blocks_vector_source_x_0_2, '0', m17_m17_coder_0, '0']
- [m17_m17_coder_0, '0', blocks_throttle2_0, '0']
metadata:
file_format: 1
grc_version: 3.10.10.0

BIN
examples/m17_tx.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -138,6 +138,8 @@ void m17_coder_impl::set_type(short type)
int countin=0;
uint32_t countout=0;
float frame_buff_tmp[192];
uint32_t frame_buff_count_tmp;
uint8_t enc_bits[SYM_PER_PLD*2]; //type-2 bits, unpacked
uint8_t rf_bits[SYM_PER_PLD*2]; //type-4 bits, unpacked
@ -149,120 +151,30 @@ void m17_coder_impl::set_type(short type)
while (countout<(uint32_t)noutput_items) {
if (countin+16<=noutput_items)
{if(_got_lsf) //stream frames
{for (int i=0;i<16;i++) {data[i]=in[countin];countin++;}
if(_got_lsf) //stream frames
{
//we could discard the data we already have
for (int i=0;i<16;i++) {data[i]=in[countin];countin++;}
//send stream frame syncword
send_syncword(out,&countout,SYNC_STR);
//derive the LICH_CNT from the Frame Number
lich_cnt=_fn%6;
//extract LICH from the whole LSF
switch(lich_cnt)
{
case 0:
lich[0]=lsf.dst[0];
lich[1]=lsf.dst[1];
lich[2]=lsf.dst[2];
lich[3]=lsf.dst[3];
lich[4]=lsf.dst[4];
break;
case 1:
lich[0]=lsf.dst[5];
lich[1]=lsf.src[0];
lich[2]=lsf.src[1];
lich[3]=lsf.src[2];
lich[4]=lsf.src[3];
break;
case 2:
lich[0]=lsf.src[4];
lich[1]=lsf.src[5];
lich[2]=lsf.type[0];
lich[3]=lsf.type[1];
lich[4]=lsf.meta[0];
break;
case 3:
lich[0]=lsf.meta[1];
lich[1]=lsf.meta[2];
lich[2]=lsf.meta[3];
lich[3]=lsf.meta[4];
lich[4]=lsf.meta[5];
break;
case 4:
lich[0]=lsf.meta[6];
lich[1]=lsf.meta[7];
lich[2]=lsf.meta[8];
lich[3]=lsf.meta[9];
lich[4]=lsf.meta[10];
break;
case 5:
lich[0]=lsf.meta[11];
lich[1]=lsf.meta[12];
lich[2]=lsf.meta[13];
lich[3]=lsf.crc[0];
lich[4]=lsf.crc[1];
break;
default:
;
break;
}
lich[5]=lich_cnt<<5;
extract_LICH(lich, lich_cnt, &lsf);
//encode the LICH
uint32_t val;
val=golay24_encode((lich[0]<<4)|(lich[1]>>4));
lich_encoded[0]=(val>>16)&0xFF;
lich_encoded[1]=(val>>8)&0xFF;
lich_encoded[2]=(val>>0)&0xFF;
val=golay24_encode(((lich[1]&0x0F)<<8)|lich[2]);
lich_encoded[3]=(val>>16)&0xFF;
lich_encoded[4]=(val>>8)&0xFF;
lich_encoded[5]=(val>>0)&0xFF;
val=golay24_encode((lich[3]<<4)|(lich[4]>>4));
lich_encoded[6]=(val>>16)&0xFF;
lich_encoded[7]=(val>>8)&0xFF;
lich_encoded[8]=(val>>0)&0xFF;
val=golay24_encode(((lich[4]&0x0F)<<8)|lich[5]);
lich_encoded[9]=(val>>16)&0xFF;
lich_encoded[10]=(val>>8)&0xFF;
lich_encoded[11]=(val>>0)&0xFF;
encode_LICH(lich_encoded, lich);
//unpack LICH (12 bytes)
memset(enc_bits, 0, SYM_PER_PLD*2);
for(uint8_t i=0; i<12; i++)
{
for(uint8_t j=0; j<8; j++)
enc_bits[i*8+j]=(lich_encoded[i]>>(7-j))&1;
}
unpack_LICH(enc_bits, lich_encoded);
//encode the rest of the frame
//encode the rest of the frame (starting at bit 96 - 0..95 are filled with LICH)
// conv_encode_stream_frame(&enc_bits[96], data, finished ? (_fn | 0x8000) : _fn); JMF review
conv_encode_stream_frame(&enc_bits[96], data, _fn);
//reorder bits
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
rf_bits[i]=enc_bits[intrl_seq[i]];
reorder_bits(rf_bits, enc_bits);
//randomize
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
{
if((rand_seq[i/8]>>(7-(i%8)))&1) //flip bit if '1'
{
if(rf_bits[i])
rf_bits[i]=0;
else
rf_bits[i]=1;
}
}
randomize_bits(rf_bits);
//send dummy symbols (debug)
/*float s=0.0;
@ -288,51 +200,41 @@ void m17_coder_impl::set_type(short type)
}
else //LSF
{
// for (int i=0;i<6;i++) {lsf.dst[i]=in[countin];countin++;}
// for (int i=0;i<6;i++) {lsf.src[i]=in[countin];countin++;}
// for (int i=0;i<2;i++) {lsf.type[i]=in[countin];countin++;}
// for (int i=0;i<14;i++) {lsf.meta[i]=in[countin];countin++;}
for (int i=0;i<16;i++) {data[i]=in[countin];countin++;}
//calculate LSF CRC
// uint16_t ccrc=LSF_CRC(&lsf);
// lsf.crc[0]=ccrc>>8;
// lsf.crc[1]=ccrc&0xFF;
_got_lsf=1;
// printf("got_lsf=1\n");
//send out the preamble and LSF
send_preamble(frame_buff_tmp, &frame_buff_count_tmp, 0); //0 - LSF preamble, as opposed to 1 - BERT preamble
for(uint16_t i=0; i<SYM_PER_FRA; i++) //40ms * 4800 - 8 (syncword)
{
out[countout]=frame_buff_tmp[i];
countout++;
}
//send LSF syncword
send_syncword(frame_buff_tmp,&frame_buff_count_tmp,SYNC_LSF);
for(uint16_t i=0; i<SYM_PER_SWD; i++) //40ms * 4800 - 8 (syncword)
{
out[countout]=frame_buff_tmp[i];
countout++;
}
//encode LSF data
conv_encode_LSF(enc_bits, &lsf);
//send out the preamble and LSF
//send_Preamble(0,out,&countout); //0 - LSF preamble, as opposed to 1 - BERT preamble
send_preamble(out, &countout, 0);
//send LSF syncword
send_syncword(out,&countout,SYNC_LSF);
//reorder bits
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
rf_bits[i]=enc_bits[intrl_seq[i]];
reorder_bits(rf_bits, enc_bits);
//randomize
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
{
if((rand_seq[i/8]>>(7-(i%8)))&1) //flip bit if '1'
{
if(rf_bits[i])
rf_bits[i]=0;
else
rf_bits[i]=1;
}
}
randomize_bits(rf_bits);
float s;
//send LSF data
send_data(frame_buff_tmp, &frame_buff_count_tmp, rf_bits);
for(uint16_t i=0; i<SYM_PER_PLD; i++) //40ms * 4800 - 8 (syncword)
{
s=symbol_map[rf_bits[2*i]*2+rf_bits[2*i+1]];
out[countout]=s;
out[countout]=frame_buff_tmp[i];
countout++;
}