kopia lustrzana https://github.com/proto17/dji_droneid
Added decode block
rodzic
08cd68ab52
commit
94297ff21c
|
@ -7,5 +7,5 @@
|
|||
#
|
||||
|
||||
install(FILES
|
||||
droneid_misc_utils.block.yml DESTINATION share/gnuradio/grc/blocks
|
||||
droneid_decode.block.yml DESTINATION share/gnuradio/grc/blocks
|
||||
)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
id: droneid_decode
|
||||
label: decode
|
||||
category: '[droneid]'
|
||||
|
||||
templates:
|
||||
imports: from gnuradio import droneid
|
||||
make: droneid.decode(${debug_path})
|
||||
|
||||
# Make one 'parameters' list entry for every parameter you want settable from the GUI.
|
||||
# Keys include:
|
||||
# * id (makes the value accessible as keyname, e.g. in the make entry)
|
||||
# * label (label shown in the GUI)
|
||||
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
|
||||
# * default
|
||||
parameters:
|
||||
- id: debug_path
|
||||
label: Debug Path
|
||||
dtype: string
|
||||
default: /tmp/bursts
|
||||
|
||||
# Make one 'inputs' list entry per input and one 'outputs' list entry per output.
|
||||
# Keys include:
|
||||
# * label (an identifier for the GUI)
|
||||
# * domain (optional - stream or message. Default is stream)
|
||||
# * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
|
||||
# * vlen (optional - data stream vector length. Default is 1)
|
||||
# * optional (optional - set to 1 for optional inputs. Default is 0)
|
||||
inputs:
|
||||
- label: pdus
|
||||
domain: message
|
||||
optional: 0
|
||||
|
||||
outputs:
|
||||
- label: pdus
|
||||
domain: message
|
||||
optional: 1
|
||||
|
||||
# 'file_format' specifies the version of the GRC yml format used in the file
|
||||
# and should usually not be changed.
|
||||
file_format: 1
|
|
@ -11,5 +11,6 @@
|
|||
########################################################################
|
||||
install(FILES
|
||||
api.h
|
||||
misc_utils.h DESTINATION include/gnuradio/droneid
|
||||
misc_utils.h
|
||||
decode.h DESTINATION include/gnuradio/droneid
|
||||
)
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2022 gr-droneid author.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_DRONEID_DECODE_H
|
||||
#define INCLUDED_DRONEID_DECODE_H
|
||||
|
||||
#include <gnuradio/droneid/api.h>
|
||||
#include <gnuradio/sync_block.h>
|
||||
|
||||
namespace gr {
|
||||
namespace droneid {
|
||||
|
||||
/*!
|
||||
* \brief <+description of block+>
|
||||
* \ingroup droneid
|
||||
*
|
||||
*/
|
||||
class DRONEID_API decode : virtual public gr::sync_block
|
||||
{
|
||||
public:
|
||||
typedef std::shared_ptr<decode> sptr;
|
||||
|
||||
/*!
|
||||
* \brief Return a shared_ptr to a new instance of droneid::decode.
|
||||
*
|
||||
* To avoid accidental use of raw pointers, droneid::decode's
|
||||
* constructor is in a private implementation
|
||||
* class. droneid::decode::make is the public interface for
|
||||
* creating new instances.
|
||||
*/
|
||||
static sptr make(const std::string & debug_path);
|
||||
};
|
||||
|
||||
} // namespace droneid
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_DRONEID_DECODE_H */
|
|
@ -13,6 +13,7 @@ include(GrPlatform) #define LIB_SUFFIX
|
|||
|
||||
list(APPEND droneid_sources
|
||||
misc_utils.cc
|
||||
decode_impl.cc
|
||||
)
|
||||
|
||||
set(droneid_sources "${droneid_sources}" PARENT_SCOPE)
|
||||
|
@ -23,6 +24,7 @@ endif(NOT droneid_sources)
|
|||
|
||||
add_library(gnuradio-droneid SHARED ${droneid_sources})
|
||||
target_link_libraries(gnuradio-droneid gnuradio::gnuradio-runtime gnuradio-fft gnuradio-filter)
|
||||
target_link_libraries(gnuradio-droneid turbofec boost_filesystem)
|
||||
target_include_directories(gnuradio-droneid
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||
PUBLIC $<INSTALL_INTERFACE:include>
|
||||
|
@ -56,6 +58,7 @@ include(GrTest)
|
|||
#include_directories()
|
||||
# List all files that contain Boost.UTF unit tests here
|
||||
list(APPEND test_droneid_sources
|
||||
qa_decode.cc
|
||||
)
|
||||
# Anything we need to link to for the unit tests go here
|
||||
list(APPEND GR_TEST_TARGET_DEPS gnuradio-droneid)
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2022 gr-droneid author.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "decode_impl.h"
|
||||
#include <gnuradio/io_signature.h>
|
||||
extern "C" {
|
||||
#include <turbofec/rate_match.h>
|
||||
#include <turbofec/turbo.h>
|
||||
}
|
||||
|
||||
#include <gnuradio/io_signature.h>
|
||||
#include "decode_impl.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <gnuradio/droneid/misc_utils.h>
|
||||
#include <chrono>
|
||||
|
||||
// This line is required before the include of CRC.h so that it actually loads the CRC_24_LTEA definition
|
||||
#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
#include <CRC.h>
|
||||
|
||||
namespace gr {
|
||||
namespace droneid {
|
||||
|
||||
using path = boost::filesystem::path;
|
||||
|
||||
decode::sptr
|
||||
decode::make(const std::string & debug_path) {
|
||||
return gnuradio::get_initial_sptr
|
||||
(new decode_impl(debug_path));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The private constructor
|
||||
*/
|
||||
decode_impl::decode_impl(const std::string & debug_path)
|
||||
: gr::sync_block("decode",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0)),
|
||||
debug_path_(debug_path){
|
||||
message_port_register_in(pmt::mp(input_pdu_port_name_));
|
||||
message_port_register_out(pmt::mp(output_pdu_port_name_));
|
||||
|
||||
set_msg_handler(pmt::mp(input_pdu_port_name_), [this](const pmt::pmt_t & pdu){
|
||||
this->handle_pdu(pdu);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Our virtual destructor.
|
||||
*/
|
||||
decode_impl::~decode_impl() {
|
||||
}
|
||||
|
||||
std::vector<int8_t> decode_impl::qpsk_to_bits(const std::vector<gr_complex> &samples) {
|
||||
std::vector<int8_t> bits(samples.size() * 2);
|
||||
|
||||
auto * bit_vec_ptr = &bits[0];
|
||||
|
||||
std::for_each(samples.begin(), samples.end(), [&bit_vec_ptr](const gr_complex & sample) {
|
||||
if (sample.real() > 0 && sample.imag() > 0) {
|
||||
*bit_vec_ptr++ = 0;
|
||||
*bit_vec_ptr++ = 0;
|
||||
} else if (sample.real() > 0 && sample.imag() < 0) {
|
||||
*bit_vec_ptr++ = 0;
|
||||
*bit_vec_ptr++ = 1;
|
||||
} else if (sample.real() < 0 && sample.imag() > 0) {
|
||||
*bit_vec_ptr++ = 1;
|
||||
*bit_vec_ptr++ = 0;
|
||||
} else {
|
||||
*bit_vec_ptr++ = 1;
|
||||
*bit_vec_ptr++ = 1;
|
||||
}
|
||||
});
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
void decode_impl::handle_pdu(const pmt::pmt_t & pdu) {
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
const pmt::pmt_t meta = pmt::car(pdu);
|
||||
const pmt::pmt_t vec = pmt::cdr(pdu);
|
||||
|
||||
const auto samples = pmt::c32vector_elements(vec);
|
||||
|
||||
if (samples.size() != 3600) {
|
||||
std::cout << "Invalid number of samples. Expected 3600, got " << samples.size() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
auto bits = qpsk_to_bits(samples);
|
||||
|
||||
if (! debug_path_.empty()) {
|
||||
misc_utils::write((path(debug_path_) / "bits").string(), &bits[0], sizeof(bits[0]), bits.size());
|
||||
const auto bit_string = misc_utils::bit_vec_to_string(bits);
|
||||
misc_utils::write((path(debug_path_) / "bit_string").string(), &bit_string[0], sizeof(bit_string[0]), bit_string.size());
|
||||
}
|
||||
// misc_utils::print_bits(bits);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setup and run the Turbo decoder
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const size_t input_file_bit_count = 7200;
|
||||
|
||||
const int turbo_iterations = 4;
|
||||
const int turbo_decoder_bit_count = 1412; // Number of bits that the Turbo decoder will take in
|
||||
const int expected_payload_bytes = 176; // Number of bytes that the Turbo decoder will output
|
||||
const int expected_payload_bits = expected_payload_bytes * 8;
|
||||
|
||||
// Allocate buffers for the Turbo decoder
|
||||
std::vector<int8_t> d1(turbo_decoder_bit_count);
|
||||
std::vector<int8_t> d2(turbo_decoder_bit_count);
|
||||
std::vector<int8_t> d3(turbo_decoder_bit_count);
|
||||
std::vector<uint8_t> decoded_bytes(expected_payload_bytes);
|
||||
|
||||
// Create the required structures to run the Turbo decoder
|
||||
struct lte_rate_matcher * rate_matcher = lte_rate_matcher_alloc();
|
||||
struct tdecoder * turbo_decoder = alloc_tdec();
|
||||
struct lte_rate_matcher_io rate_matcher_io = {
|
||||
.D = turbo_decoder_bit_count,
|
||||
.E = input_file_bit_count,
|
||||
.d = {&d1[0], &d2[0], &d3[0]},
|
||||
.e = &bits[0]
|
||||
};
|
||||
|
||||
// Setup the rate matching logic
|
||||
lte_rate_match_rv(rate_matcher, &rate_matcher_io, 0);
|
||||
|
||||
// Run the turbo decoder (will do rate matching as well)
|
||||
const int decode_status = lte_turbo_decode(turbo_decoder, expected_payload_bits, turbo_iterations,
|
||||
&decoded_bytes[0], &d1[0], &d2[0], &d3[0]);
|
||||
|
||||
if (decode_status != 0) {
|
||||
std::cerr << "Failed to decode\n";
|
||||
} else {
|
||||
for (const auto & b : decoded_bytes) {
|
||||
fprintf(stdout, "%02x", b);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
const auto crc_out = CRC::Calculate(&decoded_bytes[0], decoded_bytes.size(), CRC::CRC_24_LTEA());
|
||||
if (crc_out != 0) {
|
||||
std::cerr << "CRC Check Failed!\n";
|
||||
}
|
||||
|
||||
message_port_pub(pmt::mp(output_pdu_port_name_), pmt::cons(pmt::make_dict(), pmt::init_u8vector(decoded_bytes.size(), decoded_bytes)));
|
||||
}
|
||||
|
||||
free_tdec(turbo_decoder);
|
||||
lte_rate_matcher_free(rate_matcher);
|
||||
|
||||
const auto end_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
std::cout << "Time: " << std::chrono::duration<float>(end_time - start_time).count() << "\n";
|
||||
}
|
||||
|
||||
int
|
||||
decode_impl::work(int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items) {
|
||||
|
||||
// Do <+signal processing+>
|
||||
|
||||
// Tell runtime system how many output items we produced.
|
||||
return noutput_items;
|
||||
}
|
||||
|
||||
} /* namespace droneid */
|
||||
} /* namespace gr */
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2022 gr-droneid author.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_DRONEID_DECODE_IMPL_H
|
||||
#define INCLUDED_DRONEID_DECODE_IMPL_H
|
||||
|
||||
#include <gnuradio/droneid/decode.h>
|
||||
|
||||
namespace gr {
|
||||
namespace droneid {
|
||||
|
||||
class decode_impl : public decode {
|
||||
private:
|
||||
const std::string input_pdu_port_name_ = "pdus";
|
||||
const std::string output_pdu_port_name_ = "pdus";
|
||||
|
||||
const std::string debug_path_;
|
||||
|
||||
static std::vector<int8_t> qpsk_to_bits(const std::vector<gr_complex> & samples);
|
||||
// Nothing to declare in this block.
|
||||
|
||||
public:
|
||||
decode_impl(const std::string & debug_path);
|
||||
|
||||
~decode_impl();
|
||||
|
||||
// Where all the action really happens
|
||||
int work(
|
||||
int noutput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items
|
||||
);
|
||||
|
||||
void handle_pdu(const pmt::pmt_t & pdu);
|
||||
};
|
||||
|
||||
} // namespace droneid
|
||||
} // namespace gr
|
||||
|
||||
#endif /* INCLUDED_DRONEID_DECODE_IMPL_H */
|
|
@ -0,0 +1,21 @@
|
|||
/* -*- c++ -*- */
|
||||
/*
|
||||
* Copyright 2022 gr-droneid author.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <gnuradio/attributes.h>
|
||||
#include <gnuradio/droneid/decode.h>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
namespace gr {
|
||||
namespace droneid {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_decode_replace_with_specific_test_name)
|
||||
{
|
||||
// Put test here
|
||||
}
|
||||
|
||||
} /* namespace droneid */
|
||||
} /* namespace gr */
|
|
@ -29,7 +29,8 @@ include(GrPybind)
|
|||
########################################################################
|
||||
|
||||
list(APPEND droneid_python_files
|
||||
misc_utils_python.cc python_bindings.cc)
|
||||
misc_utils_python.cc
|
||||
decode_python.cc python_bindings.cc)
|
||||
|
||||
GR_PYBIND_MAKE_OOT(droneid
|
||||
../../..
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2022 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
/***********************************************************************************/
|
||||
/* This file is automatically generated using bindtool and can be manually edited */
|
||||
/* The following lines can be configured to regenerate this file during cmake */
|
||||
/* If manual edits are made, the following tags should be modified accordingly. */
|
||||
/* BINDTOOL_GEN_AUTOMATIC(0) */
|
||||
/* BINDTOOL_USE_PYGCCXML(0) */
|
||||
/* BINDTOOL_HEADER_FILE(decode.h) */
|
||||
/* BINDTOOL_HEADER_FILE_HASH(4384f371a0acd77c255acf790ea502c6) */
|
||||
/***********************************************************************************/
|
||||
|
||||
#include <pybind11/complex.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
#include <gnuradio/droneid/decode.h>
|
||||
// pydoc.h is automatically generated in the build directory
|
||||
#include <decode_pydoc.h>
|
||||
|
||||
void bind_decode(py::module& m)
|
||||
{
|
||||
|
||||
using decode = ::gr::droneid::decode;
|
||||
|
||||
|
||||
py::class_<decode,
|
||||
gr::sync_block,
|
||||
gr::block,
|
||||
gr::basic_block,
|
||||
std::shared_ptr<decode>>(m, "decode", D(decode))
|
||||
|
||||
.def(py::init(&decode::make), py::arg("debug_path"), D(decode, make))
|
||||
|
||||
|
||||
;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2022 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNU Radio
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
#include "pydoc_macros.h"
|
||||
#define D(...) DOC(gr, droneid, __VA_ARGS__)
|
||||
/*
|
||||
This file contains placeholders for docstrings for the Python bindings.
|
||||
Do not edit! These were automatically extracted during the binding process
|
||||
and will be overwritten during the build process
|
||||
*/
|
||||
|
||||
|
||||
static const char* __doc_gr_droneid_decode = R"doc()doc";
|
||||
|
||||
|
||||
static const char* __doc_gr_droneid_decode_decode = R"doc()doc";
|
||||
|
||||
|
||||
static const char* __doc_gr_droneid_decode_make = R"doc()doc";
|
|
@ -22,6 +22,7 @@ namespace py = pybind11;
|
|||
/**************************************/
|
||||
// BINDING_FUNCTION_PROTOTYPES(
|
||||
void bind_misc_utils(py::module& m);
|
||||
void bind_decode(py::module& m);
|
||||
// ) END BINDING_FUNCTION_PROTOTYPES
|
||||
|
||||
|
||||
|
@ -53,5 +54,6 @@ PYBIND11_MODULE(droneid_python, m)
|
|||
/**************************************/
|
||||
// BINDING_FUNCTION_CALLS(
|
||||
bind_misc_utils(m);
|
||||
bind_decode(m);
|
||||
// ) END BINDING_FUNCTION_CALLS
|
||||
}
|
Ładowanie…
Reference in New Issue