user selectable callsign decoding + improved meta information display

main
Jean-Michel Friedt 2024-06-19 19:15:09 +02:00
parent 161688ce20
commit b7036eab41
8 changed files with 145 additions and 125 deletions

View File

@ -1,7 +1,7 @@
## Compiling for GNU Radio ## Compiling for GNU Radio
The default targetted version is GNU Radio 3.10 (``main`` branch). Tested on Debian/GNU Linux sid with GNU Radio The default targetted version is GNU Radio 3.10 (``main`` branch). Tested on Debian/GNU Linux sid with GNU Radio
3.10.10.0 (Python 3.11.9) assuming the following dependencies are installed: 3.10.10.0 (Python 3.11.9) and Ubuntu 24.04 LTS with GNU Radio 3.10.9.2, assuming the following dependencies are installed:
``` ```
sudo apt install git cmake build-essential doxygen gnuradio sudo apt install git cmake build-essential doxygen gnuradio
@ -22,7 +22,8 @@ will finish with a statement such as
``` ```
-- Set runtime path of "/usr/local/lib/python3.11/dist-packages/gnuradio/m17/m17_python.cpython-311-x86_64-linux-gnu.so" to "" -- Set runtime path of "/usr/local/lib/python3.11/dist-packages/gnuradio/m17/m17_python.cpython-311-x86_64-linux-gnu.so" to ""
``` ```
meaning that variables must be set (tested with Debian/sid) to help GNU Radio Companion find the Python libraries: Depending on Linux distribution, variables might have to be set (tested with Debian/sid, but not needed with Ubuntu 24.04 LTS)
to help GNU Radio Companion find the Python libraries:
``` ```
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/x86_64-linux-gnu/ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/x86_64-linux-gnu/

View File

@ -11,7 +11,7 @@ options:
gen_linking: dynamic gen_linking: dynamic
generate_options: qt_gui generate_options: qt_gui
hier_block_src_path: '.:' hier_block_src_path: '.:'
id: m17_streamer id: m17_loopback
max_nouts: '0' max_nouts: '0'
output_language: python output_language: python
placement: (0,0) placement: (0,0)
@ -70,7 +70,7 @@ blocks:
options: '[0, 1, 2]' options: '[0, 1, 2]'
orient: Qt.QVBoxLayout orient: Qt.QVBoxLayout
type: int type: int
value: '1' value: '0'
widget: combo_box widget: combo_box
states: states:
bus_sink: false bus_sink: false
@ -212,7 +212,7 @@ blocks:
bus_sink: false bus_sink: false
bus_source: false bus_source: false
bus_structure: null bus_structure: null
coordinate: [952, 152.0] coordinate: [960, 152.0]
rotation: 0 rotation: 0
state: enabled state: enabled
- name: blocks_null_sink_0 - name: blocks_null_sink_0
@ -283,12 +283,13 @@ blocks:
comment: 'since Meta can be a byte array, it cannot be fed with a QT GUI Entry comment: 'since Meta can be a byte array, it cannot be fed with a QT GUI Entry
string but must be a "\x00" string in the Encoder block' string but must be a "\x00" string in the Encoder block'
debug: 'False' debug: 'True'
dst_id: dst_str dst_id: dst_str
encr_subtype: enc_subtype encr_subtype: enc_subtype
encr_type: enc_type encr_type: enc_type
key: '''\x00\x00\x65\x41\xb0\x93\xff\x00'''
maxoutbuf: '0' maxoutbuf: '0'
meta: '''\x00\x00\x65\x41\xb0\x93\xff\x00\x00\x00\x00\x00\x00\x00\x00''' meta: '''\x00\x00\x65\x41\xb0\x93\xff\x00'''
minoutbuf: '0' minoutbuf: '0'
mode: mode mode: mode
src_id: src_str src_id: src_str
@ -297,7 +298,7 @@ blocks:
bus_sink: false bus_sink: false
bus_source: false bus_source: false
bus_structure: null bus_structure: null
coordinate: [320, 100.0] coordinate: [320, 92.0]
rotation: 0 rotation: 0
state: true state: true
- name: m17_m17_decoder_0 - name: m17_m17_decoder_0
@ -305,9 +306,10 @@ blocks:
parameters: parameters:
affinity: '' affinity: ''
alias: '' alias: ''
callsign: 'False'
comment: '' comment: ''
debug_ctrl: 'False' debug_ctrl: 'True'
debug_data: 'False' debug_data: 'True'
maxoutbuf: '0' maxoutbuf: '0'
minoutbuf: '0' minoutbuf: '0'
threshold: '2.0' threshold: '2.0'
@ -315,7 +317,7 @@ blocks:
bus_sink: false bus_sink: false
bus_source: false bus_source: false
bus_structure: null bus_structure: null
coordinate: [784, 152.0] coordinate: [784, 144.0]
rotation: 0 rotation: 0
state: true state: true
- name: note_0_2 - name: note_0_2

View File

@ -13,6 +13,11 @@ parameters:
dtype: bool dtype: bool
default: 'False' default: 'False'
options: ['True', 'False'] options: ['True', 'False']
- id: callsign
label: Display Callsign
dtype: bool
default: 'False'
options: ['True', 'False']
- id: threshold - id: threshold
label: Threshold label: Threshold
dtype: float dtype: float
@ -20,11 +25,12 @@ parameters:
templates: templates:
imports: from gnuradio import m17 imports: from gnuradio import m17
make: m17.m17_decoder(${debug_data},${debug_ctrl},${threshold}) make: m17.m17_decoder(${debug_data},${debug_ctrl},${threshold},${callsign})
callbacks: callbacks:
- set_debug_data(${debug_data}) - set_debug_data(${debug_data})
- set_debug_ctrl(${debug_ctrl}) - set_debug_ctrl(${debug_ctrl})
- set_threshold(${threshold}) - set_threshold(${threshold})
- set_callsign(${callsign})
# Make one 'inputs' list entry per input and one 'outputs' list entry per output. # Make one 'inputs' list entry per input and one 'outputs' list entry per output.
# Keys include: # Keys include:

View File

@ -32,9 +32,10 @@ public:
* class. m17::m17_decoder::make is the public interface for * class. m17::m17_decoder::make is the public interface for
* creating new instances. * creating new instances.
*/ */
static sptr make(bool debug_data,bool debug_ctrl,float threshold); static sptr make(bool debug_data,bool debug_ctrl,float threshold,bool callsign);
virtual void set_debug_data(bool debug)=0; virtual void set_debug_data(bool debug)=0;
virtual void set_debug_ctrl(bool debug)=0; virtual void set_debug_ctrl(bool debug)=0;
virtual void set_callsign(bool callsign)=0;
virtual void set_threshold(float threshold)=0; virtual void set_threshold(float threshold)=0;
}; };

View File

@ -33,10 +33,6 @@
#include "m17.h" #include "m17.h"
#define DECODE_CALLSIGNS
//#define SHOW_VITERBI_ERRS
//
#define CODE_MEAN -0.75 // mean(str_sync_symbols) #define CODE_MEAN -0.75 // mean(str_sync_symbols)
#define CODE_STD 8.21583836f //std(str_sync_symbols)*sqrt(length(str_sync_symbols)-1) #define CODE_STD 8.21583836f //std(str_sync_symbols)*sqrt(length(str_sync_symbols)-1)
@ -44,24 +40,25 @@ namespace gr {
namespace m17 { namespace m17 {
m17_decoder::sptr m17_decoder::sptr
m17_decoder::make(bool debug_data,bool debug_ctrl,float threshold) m17_decoder::make(bool debug_data,bool debug_ctrl,float threshold,bool callsign)
{ {
return gnuradio::get_initial_sptr return gnuradio::get_initial_sptr
(new m17_decoder_impl(debug_data,debug_ctrl,threshold)); (new m17_decoder_impl(debug_data,debug_ctrl,threshold,callsign));
} }
/* /*
* The private constructor * The private constructor
*/ */
m17_decoder_impl::m17_decoder_impl(bool debug_data,bool debug_ctrl,float threshold) m17_decoder_impl::m17_decoder_impl(bool debug_data,bool debug_ctrl,float threshold,bool callsign)
: gr::block("m17_decoder", : gr::block("m17_decoder",
gr::io_signature::make(1, 1, sizeof(float)), gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(1, 1, sizeof(char))), gr::io_signature::make(1, 1, sizeof(char))),
_debug_data(debug_data), _debug_ctrl(debug_ctrl), _threshold(threshold) _debug_data(debug_data), _debug_ctrl(debug_ctrl), _threshold(threshold), _callsign(callsign)
{set_debug_data(debug_data); {set_debug_data(debug_data);
set_debug_ctrl(debug_ctrl); set_debug_ctrl(debug_ctrl);
set_threshold(threshold); set_threshold(threshold);
set_callsign(callsign);
_expected_next_fn=0; _expected_next_fn=0;
} }
@ -87,6 +84,11 @@ namespace gr {
if (_debug_ctrl==true) printf("Debug control: true\n"); else printf("Debug control: false\n"); if (_debug_ctrl==true) printf("Debug control: true\n"); else printf("Debug control: false\n");
} }
void m17_decoder_impl::set_callsign(bool callsign)
{_callsign=callsign;
if (_callsign==true) printf("Display callsign\n"); else printf("Do not display callsign\n");
}
void void
m17_decoder_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) m17_decoder_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{ {
@ -171,17 +173,14 @@ namespace gr {
} }
//decode //decode
#ifdef SHOW_VITERBI_ERRS uint32_t e=viterbi_decode_punctured(frame_data, enc_data, puncture_pattern_2, 272, 12);
uint32_t e=
#endif
viterbi_decode_punctured(frame_data, enc_data, puncture_pattern_2, 272, 12);
uint16_t fn = (frame_data[1] << 8) | frame_data[2]; uint16_t fn = (frame_data[1] << 8) | frame_data[2];
if (_debug_data==true) { if (_debug_data==true) { //dump data - first byte is empty
//dump data - first byte is empty printf("RX FN: %04X PLD: ", fn);
printf("RX FN: %02X%02X PLD: ", frame_data[1], frame_data[2]);
} }
for(uint8_t i=3; i<19; i++) for(uint8_t i=3; i<19; i++)
{ {
if (_debug_data==true) { if (_debug_data==true) {
@ -190,11 +189,7 @@ namespace gr {
out[countout]=frame_data[i];countout++; out[countout]=frame_data[i];countout++;
} }
if (_debug_data==true) { if (_debug_data==true) {
#ifdef SHOW_VITERBI_ERRS
printf(" e=%1.1f\n", (float)e/0xFFFF); printf(" e=%1.1f\n", (float)e/0xFFFF);
#else
printf("\n");
#endif
} }
//send codec2 stream to stdout //send codec2 stream to stdout
//write(STDOUT_FILENO, &frame_data[3], 16); //write(STDOUT_FILENO, &frame_data[3], 16);
@ -219,90 +214,99 @@ namespace gr {
//debug - dump LICH //debug - dump LICH
if(lich_chunks_rcvd==0x3F) //all 6 chunks received? if(lich_chunks_rcvd==0x3F) //all 6 chunks received?
{ {
#ifdef DECODE_CALLSIGNS if (_debug_ctrl==true)
uint8_t d_dst[12], d_src[12]; //decoded strings {if (_callsign==true)
{decode_callsign_bytes(d_dst, &lsf[0]);
decode_callsign_bytes(d_dst, &lsf[0]);
decode_callsign_bytes(d_src, &lsf[6]); decode_callsign_bytes(d_src, &lsf[6]);
printf("DST: %-9s ", d_dst); //DST
if (_debug_ctrl==true) { printf("SRC: %-9s ", d_src); //SRC
//DST }
printf("DST: %-9s ", d_dst); else
{printf("DST: "); //DST
//SRC
printf("SRC: %-9s ", d_src);
#else
//DST
printf("DST: ");
for(uint8_t i=0; i<6; i++) for(uint8_t i=0; i<6; i++)
printf("%02X", lsf[i]); printf("%02X", lsf[i]);
printf(" "); printf(" ");
printf("SRC: "); //SRC
//SRC
printf("SRC: ");
for(uint8_t i=0; i<6; i++) for(uint8_t i=0; i<6; i++)
printf("%02X", lsf[6+i]); printf("%02X", lsf[6+i]);
printf(" "); printf(" ");
#endif }
}
//TYPE //TYPE
printf("TYPE: "); uint16_t type=(uint16_t)lsf[12]*0x100+lsf[13]; //big-endian
for(uint8_t i=0; i<2; i++) if (_debug_ctrl==true)
printf("%02X", lsf[12+i]); {printf("TYPE: %04X (", type);
printf(" "); if(type&&1)
printf("STREAM: ");
else
printf("PACKET: "); //shouldn't happen
if(((type>>1)&3)==1)
printf("DATA, ");
else if(((type>>1)&3)==2)
printf("VOICE, ");
else if(((type>>1)&3)==3)
printf("VOICE+DATA, ");
printf("ENCR: ");
if(((type>>3)&3)==0)
printf("PLAIN, ");
else if(((type>>3)&3)==1)
{
printf("SCRAM ");
if(((type>>5)&3)==1)
printf("8-bit, ");
else if(((type>>5)&3)==2)
printf("16-bit, ");
else if(((type>>5)&3)==3)
printf("24-bit, ");
}
else if(((type>>3)&3)==2)
printf("AES, ");
else
printf("UNK, ");
printf("CAN: %d", (type>>7)&0xF);
if((type>>11)&1)
printf(", SIGNED");
printf(") ");
}
//META //META
printf("META: "); if (_debug_ctrl==true)
{printf("META: ");
for(uint8_t i=0; i<14; i++) for(uint8_t i=0; i<14; i++)
printf("%02X", lsf[14+i]); printf("%02X", lsf[14+i]);
//printf(" ");
//CRC if(CRC_M17(lsf, 30)) //CRC
//printf("CRC: ");
//for(uint8_t i=0; i<2; i++)
//printf("%02X", lsf[28+i]);
if(CRC_M17(lsf, 30))
printf(" LSF_CRC_ERR"); printf(" LSF_CRC_ERR");
else else
printf(" LSF_CRC_OK "); printf(" LSF_CRC_OK ");
printf("\n"); printf("\n");
} }
} }
_expected_next_fn = (fn + 1) % 0x8000; _expected_next_fn = (fn + 1) % 0x8000;
} }
else //lsf else //lsf
{ {
if (_debug_ctrl==true) { if (_debug_ctrl==true) {
printf("LSF\n"); printf("{LSF}\n");
} }
//decode //decode
#ifdef SHOW_VITERBI_ERRS uint32_t e=viterbi_decode_punctured(lsf, d_soft_bit, puncture_pattern_1, 2*SYM_PER_PLD, 61);
uint32_t e=
#endif
viterbi_decode_punctured(lsf, d_soft_bit, puncture_pattern_1, 2*SYM_PER_PLD, 61);
//shift the buffer 1 position left - get rid of the encoded flushing bits //shift the buffer 1 position left - get rid of the encoded flushing bits
for(uint8_t i=0; i<30; i++) for(uint8_t i=0; i<30; i++)
lsf[i]=lsf[i+1]; lsf[i]=lsf[i+1];
//dump data //dump data
#ifdef DECODE_CALLSIGNS if (_debug_ctrl==true)
uint8_t d_dst[12], d_src[12]; //decoded strings {if (_callsign==true)
{decode_callsign_bytes(d_dst, &lsf[0]);
decode_callsign_bytes(d_dst, &lsf[0]);
decode_callsign_bytes(d_src, &lsf[6]); decode_callsign_bytes(d_src, &lsf[6]);
printf("DST: %-9s ", d_dst); //DST
if (_debug_ctrl==true) { printf("SRC: %-9s ", d_src); //SRC
//DST }
printf("DST: %-9s ", d_dst); else
{printf("DST: "); //DST
//SRC
printf("SRC: %-9s ", d_src);
#else
//DST
printf("DST: ");
for(uint8_t i=0; i<6; i++) for(uint8_t i=0; i<6; i++)
printf("%02X", lsf[i]); printf("%02X", lsf[i]);
printf(" "); printf(" ");
@ -312,7 +316,7 @@ namespace gr {
for(uint8_t i=0; i<6; i++) for(uint8_t i=0; i<6; i++)
printf("%02X", lsf[6+i]); printf("%02X", lsf[6+i]);
printf(" "); printf(" ");
#endif }
//TYPE //TYPE
printf("TYPE: "); printf("TYPE: ");
@ -335,11 +339,7 @@ namespace gr {
else else
printf("LSF_CRC_OK "); printf("LSF_CRC_OK ");
//Viterbi decoder errors //Viterbi decoder errors
#ifdef SHOW_VITERBI_ERRS
printf(" e=%1.1f\n", (float)e/0xFFFF); printf(" e=%1.1f\n", (float)e/0xFFFF);
#else
printf("\n");
#endif
} }
} }

View File

@ -20,6 +20,7 @@ private:
bool _debug_data=false; bool _debug_data=false;
bool _debug_ctrl=false; bool _debug_ctrl=false;
float _threshold=0.9; float _threshold=0.9;
bool _callsign=false;
float last[8] = {0}; //look-back buffer for finding syncwords float last[8] = {0}; //look-back buffer for finding syncwords
float pld[SYM_PER_PLD]; //raw frame symbols float pld[SYM_PER_PLD]; //raw frame symbols
@ -40,11 +41,14 @@ private:
uint8_t fl=0; //Frame=0 of LSF=1 uint8_t fl=0; //Frame=0 of LSF=1
uint8_t pushed; //counter for pushed symbols uint8_t pushed; //counter for pushed symbols
uint8_t d_dst[12], d_src[12]; //decoded strings
public: public:
m17_decoder_impl(bool debug_data,bool debug_ctrl,float threshold); m17_decoder_impl(bool debug_data,bool debug_ctrl,float threshold,bool callsign);
~m17_decoder_impl(); ~m17_decoder_impl();
void set_debug_data(bool debug); void set_debug_data(bool debug);
void set_debug_ctrl(bool debug); void set_debug_ctrl(bool debug);
void set_callsign(bool callsign);
void set_threshold(float threshold); void set_threshold(float threshold);
// Where all the action really happens // Where all the action really happens

View File

@ -26,4 +26,6 @@ static const char *__doc_gr_m17_m17_decoder_set_debug_data = R"doc()doc";
static const char *__doc_gr_m17_m17_decoder_set_debug_ctrl = R"doc()doc"; static const char *__doc_gr_m17_m17_decoder_set_debug_ctrl = R"doc()doc";
static const char *__doc_gr_m17_m17_decoder_set_callsign = R"doc()doc";
static const char *__doc_gr_m17_m17_decoder_set_threshold = R"doc()doc"; static const char *__doc_gr_m17_m17_decoder_set_threshold = R"doc()doc";

View File

@ -16,7 +16,7 @@
/* BINDTOOL_GEN_AUTOMATIC(0) */ /* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */ /* BINDTOOL_USE_PYGCCXML(0) */
/* BINDTOOL_HEADER_FILE(m17_decoder.h) */ /* BINDTOOL_HEADER_FILE(m17_decoder.h) */
/* BINDTOOL_HEADER_FILE_HASH(74e8e77389b1889023dbed48ecb9523e) */ /* BINDTOOL_HEADER_FILE_HASH(265f7a49ed1b66cdd021af3149d8dc4b) */
/***********************************************************************************/ /***********************************************************************************/
#include <pybind11/complex.h> #include <pybind11/complex.h>
@ -37,7 +37,8 @@ void bind_m17_decoder(py::module &m) {
std::shared_ptr<m17_decoder>>(m, "m17_decoder", D(m17_decoder)) std::shared_ptr<m17_decoder>>(m, "m17_decoder", D(m17_decoder))
.def(py::init(&m17_decoder::make), py::arg("debug_data"), .def(py::init(&m17_decoder::make), py::arg("debug_data"),
py::arg("debug_ctrl"), py::arg("threshold"), D(m17_decoder, make)) py::arg("debug_ctrl"), py::arg("threshold"), py::arg("callsign"),
D(m17_decoder, make))
.def("set_debug_data", &m17_decoder::set_debug_data, py::arg("debug"), .def("set_debug_data", &m17_decoder::set_debug_data, py::arg("debug"),
D(m17_decoder, set_debug_data)) D(m17_decoder, set_debug_data))
@ -45,6 +46,9 @@ void bind_m17_decoder(py::module &m) {
.def("set_debug_ctrl", &m17_decoder::set_debug_ctrl, py::arg("debug"), .def("set_debug_ctrl", &m17_decoder::set_debug_ctrl, py::arg("debug"),
D(m17_decoder, set_debug_ctrl)) D(m17_decoder, set_debug_ctrl))
.def("set_callsign", &m17_decoder::set_callsign, py::arg("callsign"),
D(m17_decoder, set_callsign))
.def("set_threshold", &m17_decoder::set_threshold, py::arg("threshold"), .def("set_threshold", &m17_decoder::set_threshold, py::arg("threshold"),
D(m17_decoder, set_threshold)) D(m17_decoder, set_threshold))