diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index ef36631..7980c48 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -19,5 +19,5 @@ install(FILES ccsds_ccsds_encoder.xml ccsds_ccsds_decoder.xml - DESTINATION share/gnuradio/grc/blocks + ccsds_correlator.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/ccsds_correlator.xml b/grc/ccsds_correlator.xml new file mode 100644 index 0000000..f01a8db --- /dev/null +++ b/grc/ccsds_correlator.xml @@ -0,0 +1,40 @@ + + + Correlator + ccsds_correlator + [CCSDS] + import ccsds + ccsds.correlator($asm, $asm_mask, $threshold, $frame_len) + + ASM + asm + 0x1acffc1d + int + + + ASM Mask + asm_mask + 0xffffffff + int + + + Threshold Mask + threshold + 0 + int + + + Frame Length + frame_len + 223 + int + + + in + byte + + + out + message + + diff --git a/include/ccsds/CMakeLists.txt b/include/ccsds/CMakeLists.txt index 6b2ee19..09296de 100644 --- a/include/ccsds/CMakeLists.txt +++ b/include/ccsds/CMakeLists.txt @@ -24,5 +24,5 @@ install(FILES api.h ccsds_encoder.h ccsds_decoder.h - DESTINATION include/ccsds + correlator.h DESTINATION include/ccsds ) diff --git a/include/ccsds/correlator.h b/include/ccsds/correlator.h new file mode 100644 index 0000000..20444a0 --- /dev/null +++ b/include/ccsds/correlator.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 André Løfaldli. + * + * This 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 3, or (at your option) + * any later version. + * + * This software 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_CCSDS_CORRELATOR_H +#define INCLUDED_CCSDS_CORRELATOR_H + +#include +#include + +namespace gr { + namespace ccsds { + + /*! + * \brief CCSDS correlator + * \ingroup ccsds + * + * looks for the attached sync marker and produces pdus containing frames + */ + class CCSDS_API correlator : virtual public gr::sync_block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief make the correlator. + * + * \param asm attached sync marker + * \param asm_mask mask for attached sync marker + * \param threshold maximum number of allowed errors in asm + * \param frame_len length of the transfer frame + */ + static sptr make(const uint64_t asm_=0x1acffc1d, + const uint64_t asm_mask=0xffffffff, + const uint8_t threshold=2, + const size_t frame_len=223); + }; + + } // namespace ccsds +} // namespace gr + +#endif /* INCLUDED_CCSDS_CORRELATOR_H */ + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6319c8a..4b08d0d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -33,7 +33,7 @@ list(APPEND ccsds_sources reed_solomon.cc ccsds_encoder_impl.cc ccsds_decoder_impl.cc - ) + correlator_impl.cc ) set(ccsds_sources "${ccsds_sources}" PARENT_SCOPE) if(NOT ccsds_sources) diff --git a/lib/correlator_impl.cc b/lib/correlator_impl.cc new file mode 100644 index 0000000..85d8fd4 --- /dev/null +++ b/lib/correlator_impl.cc @@ -0,0 +1,148 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 André Løfaldli. + * + * This 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 3, or (at your option) + * any later version. + * + * This software 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "correlator_impl.h" + +#if 0 +#define debug_print printf +#else +#define debug_print +#endif + +namespace gr { + namespace ccsds { + + correlator::sptr + correlator::make(const uint64_t asm_, const uint64_t asm_mask, + const uint8_t threshold, const size_t frame_len) + { + return gnuradio::get_initial_sptr + (new correlator_impl(asm_, asm_mask, threshold, frame_len)); + } + + correlator_impl::correlator_impl(const uint64_t asm_, const uint64_t asm_mask, + const uint8_t threshold, const size_t frame_len) + : gr::sync_block("correlator", + gr::io_signature::make(1, 1, sizeof(uint8_t)), + gr::io_signature::make(0, 0, 0)), + d_asm(asm_), d_asm_mask(asm_mask), + d_threshold(threshold), d_frame_len(frame_len), + d_frame_count(0), d_ambiguity(NONE) + { + message_port_register_out(pmt::mp("out")); + d_frame_buffer = (uint8_t *)malloc(frame_len * sizeof(uint8_t)); + enter_state(SEARCH); + } + + correlator_impl::~correlator_impl() { + free(d_frame_buffer); + } + + int + correlator_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const uint8_t *in = (const uint8_t *) input_items[0]; + + uint64_t count = 0; + while (count < noutput_items) { + switch (d_state) { + case SEARCH: + d_asm_buf = (d_asm_buf << 1) | (in[count++] & 0x01); + if (check_asm(d_asm_buf)) { + d_ambiguity = NONE; + enter_state(LOCK); + } else if (check_asm(d_asm_buf ^ 0xffffffffffffffff)) { + d_ambiguity = INVERTED; + enter_state(LOCK); + } + break; + case LOCK: + d_byte_buf = (d_byte_buf << 1) | (in[count++] & 0x01); + d_bit_ctr++; + if (d_bit_ctr == 8) { + if (d_ambiguity == NONE) { + d_frame_buffer[d_frame_buffer_len] = d_byte_buf; + } else if (d_ambiguity == INVERTED) { + d_frame_buffer[d_frame_buffer_len] = d_byte_buf ^ 0xff; + } + d_frame_buffer_len++; + d_bit_ctr = 0; + } + if (d_frame_buffer_len == d_frame_len) { + publish_msg(); + d_frame_count++; + enter_state(SEARCH); + } + break; + } + } + return noutput_items; + } + + bool correlator_impl::check_asm(const uint64_t asm_buf) { + debug_print("check_asm\n"); + + uint64_t nerrors = 0; + const uint64_t syndrome = (asm_buf ^ d_asm) & d_asm_mask; + volk_64u_popcnt(&nerrors, syndrome); + return nerrors <= (uint64_t)d_threshold; + } + + void correlator_impl::enter_state(const state_t state) { + debug_print("enter_state "); + + switch (state) { + case SEARCH: + debug_print("SEARCH\n"); + + d_asm_buf = 0; + break; + case LOCK: + debug_print("LOCK\n"); + + d_byte_buf = 0; + d_bit_ctr = 0; + d_frame_buffer_len = 0; + break; + } + d_state = state; + } + + void correlator_impl::publish_msg() { + debug_print("publish_msg #%lu\n", d_frame_count); + + pmt::pmt_t meta = pmt::make_dict(); + meta = dict_add(meta, pmt::intern("frame_count"), + pmt::from_uint64(d_frame_count)); + const pmt::pmt_t data = pmt::init_u8vector(d_frame_len, d_frame_buffer); + message_port_pub(pmt::mp("out"), pmt::cons(meta, data)); + } + + } /* namespace ccsds */ +} /* namespace gr */ + diff --git a/lib/correlator_impl.h b/lib/correlator_impl.h new file mode 100644 index 0000000..4de46bc --- /dev/null +++ b/lib/correlator_impl.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 André Løfaldli. + * + * This 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 3, or (at your option) + * any later version. + * + * This software 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_CCSDS_CORRELATOR_IMPL_H +#define INCLUDED_CCSDS_CORRELATOR_IMPL_H + +#include +#include + +namespace gr { + namespace ccsds { + + enum state_t { SEARCH, LOCK }; + enum ambiguity_t { NONE, INVERTED }; + + class correlator_impl : public correlator { + private: + const uint64_t d_asm, d_asm_mask; + const uint8_t d_threshold; + const size_t d_frame_len; + + uint64_t d_asm_buf; + uint8_t *d_frame_buffer; + size_t d_frame_buffer_len; + uint8_t d_bit_ctr, d_byte_buf; + + state_t d_state; + ambiguity_t d_ambiguity; + uint64_t d_frame_count; + + public: + correlator_impl(const uint64_t asm_, const uint64_t asm_mask, + const uint8_t threshold, const size_t frame_len); + ~correlator_impl(); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + bool check_asm(const uint64_t asm_buf); + void enter_state(const state_t state); + void publish_msg(); + }; + + } // namespace ccsds +} // namespace gr + +#endif /* INCLUDED_CCSDS_CORRELATOR_IMPL_H */ + diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 7b4fe6c..b85a766 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -43,3 +43,4 @@ set(GR_TEST_TARGET_DEPS gnuradio-ccsds) set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) GR_ADD_TEST(qa_ccsds_encoder ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_ccsds_encoder.py) GR_ADD_TEST(qa_ccsds_decoder ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_ccsds_decoder.py) +GR_ADD_TEST(qa_correlator ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_correlator.py) diff --git a/python/qa_correlator.py b/python/qa_correlator.py new file mode 100755 index 0000000..932b24d --- /dev/null +++ b/python/qa_correlator.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2018 André Løfaldli. +# +# This 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 3, or (at your option) +# any later version. +# +# This software 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 software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import time +import random +from gnuradio import gr, gr_unittest +from gnuradio import blocks, digital +import pmt +import ccsds_swig as ccsds + +class qa_correlator (gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def test_001_t (self): + asm = (0x1a, 0xcf, 0xfc, 0x1d) + frame_len = 223 + random_data = tuple(random.randint(0, 255) for _ in range(frame_len)) + + data_in = asm + random_data + + src = blocks.vector_source_b(data_in, repeat=True) + unpack = blocks.unpack_k_bits_bb(8) + corr = ccsds.correlator(0x1acffc1d, 0xffffffff, 0, frame_len) + dbg = blocks.message_debug() + self.tb.connect(src, unpack, corr) + self.tb.msg_connect((corr, 'out'), (dbg, 'store')) + self.tb.start() + + while dbg.num_messages() < 1: + time.sleep(0.1) + + self.tb.stop() + self.tb.wait() + + msg = dbg.get_message(0) + data_out = tuple(pmt.to_python(pmt.cdr(msg))) + + assert frame_len == len(data_out) + assert random_data == data_out + + def test_002_inverted_bits (self): + asm = (0x1a, 0xcf, 0xfc, 0x1d) + frame_len = 223 + random_data = tuple(random.randint(0, 255) for _ in range(frame_len)) + + data_in = asm + random_data + + src = blocks.vector_source_b(data_in, repeat=True) + unpack = blocks.unpack_k_bits_bb(8) + mapper = digital.map_bb((1,0)) + corr = ccsds.correlator(0x1acffc1d, 0xffffffff, 0, frame_len) + dbg = blocks.message_debug() + self.tb.connect(src, unpack, mapper, corr) + self.tb.msg_connect((corr, 'out'), (dbg, 'store')) + self.tb.start() + + while dbg.num_messages() < 1: + time.sleep(0.1) + + self.tb.stop() + self.tb.wait() + + msg = dbg.get_message(0) + data_out = tuple(pmt.to_python(pmt.cdr(msg))) + + assert frame_len == len(data_out) + assert random_data == data_out + + +if __name__ == '__main__': + gr_unittest.run(qa_correlator, "qa_correlator.xml") diff --git a/swig/ccsds_swig.i b/swig/ccsds_swig.i index e2f1903..51fef57 100644 --- a/swig/ccsds_swig.i +++ b/swig/ccsds_swig.i @@ -10,6 +10,7 @@ %{ #include "ccsds/ccsds_encoder.h" #include "ccsds/ccsds_decoder.h" +#include "ccsds/correlator.h" %} @@ -17,3 +18,5 @@ GR_SWIG_BLOCK_MAGIC2(ccsds, ccsds_encoder); %include "ccsds/ccsds_decoder.h" GR_SWIG_BLOCK_MAGIC2(ccsds, ccsds_decoder); +%include "ccsds/correlator.h" +GR_SWIG_BLOCK_MAGIC2(ccsds, correlator);