2018-07-18 18:46:08 +02:00
|
|
|
/* -*- c++ -*- */
|
|
|
|
/*
|
|
|
|
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
|
|
|
|
*
|
|
|
|
* Copyright (C) 2018, Libre Space Foundation <http://librespacefoundation.org/>
|
|
|
|
*
|
|
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <gnuradio/io_signature.h>
|
|
|
|
#include "lrpt_sync_impl.h"
|
|
|
|
#include <satnogs/log.h>
|
2018-08-02 15:17:12 +02:00
|
|
|
#include <satnogs/utils.h>
|
2018-07-18 18:46:08 +02:00
|
|
|
|
|
|
|
#include <volk/volk.h>
|
|
|
|
#include <gnuradio/blocks/count_bits.h>
|
|
|
|
|
2019-09-12 15:25:10 +02:00
|
|
|
namespace gr {
|
|
|
|
namespace satnogs {
|
2018-07-18 18:46:08 +02:00
|
|
|
|
|
|
|
lrpt_sync::sptr
|
2019-09-12 15:25:10 +02:00
|
|
|
lrpt_sync::make(size_t threshold)
|
2018-07-18 18:46:08 +02:00
|
|
|
{
|
2019-09-12 15:25:10 +02:00
|
|
|
return gnuradio::get_initial_sptr(new lrpt_sync_impl(threshold));
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The private constructor
|
|
|
|
*/
|
2019-09-12 15:25:10 +02:00
|
|
|
lrpt_sync_impl::lrpt_sync_impl(size_t threshold) :
|
|
|
|
gr::sync_block("lrpt_sync",
|
|
|
|
gr::io_signature::make(1, 1, sizeof(gr_complex)),
|
|
|
|
gr::io_signature::make(0, 0, 0)),
|
|
|
|
d_thresh(threshold),
|
|
|
|
d_asm_coded(0xd49c24ff2686b),
|
|
|
|
d_asm_coded_len(52),
|
|
|
|
d_asm_coded_mask((1ULL << d_asm_coded_len) - 1),
|
|
|
|
/*
|
|
|
|
* We process the data in a multiple of 2 frames and a UW
|
|
|
|
* sync word
|
|
|
|
*/
|
|
|
|
d_window((72 + 8) / 2),
|
|
|
|
/* Each CADU has the 4 byte ASM and a VCDU of 1020 bytes*/
|
|
|
|
/*
|
|
|
|
* NOTE:
|
|
|
|
* Metop violates the standard as many times as possible...
|
|
|
|
* The frame should contain 128 RS check symbols at the end.
|
|
|
|
* For some unknown reasons, it seems that the RS encoding is not performed.
|
|
|
|
* Thus, they dropped the check symbols at the end of the frame.
|
|
|
|
*/
|
|
|
|
d_coded_cadu_len(1020 * 2 + 4 * 2 - 128 * 2),
|
|
|
|
d_frame_sync(false),
|
|
|
|
d_received(0),
|
|
|
|
d_rotate(1.0, 0.0),
|
|
|
|
d_qpsk(digital::constellation_qpsk::make()),
|
|
|
|
d_shift_reg0(0x0),
|
|
|
|
d_shift_reg1(0x0),
|
|
|
|
d_shift_reg2(0x0),
|
|
|
|
d_shift_reg3(0x0)
|
2018-07-18 18:46:08 +02:00
|
|
|
{
|
|
|
|
set_output_multiple(d_window);
|
2019-09-12 15:25:10 +02:00
|
|
|
const int alignment_multiple = volk_get_alignment() / sizeof(gr_complex);
|
|
|
|
set_alignment(std::max(1, alignment_multiple));
|
|
|
|
d_rotate_pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
|
|
|
volk_get_alignment());
|
|
|
|
if (!d_rotate_pi2) {
|
2018-07-18 18:46:08 +02:00
|
|
|
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
|
|
|
}
|
|
|
|
|
2019-09-12 15:25:10 +02:00
|
|
|
d_rotate_2pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
|
|
|
volk_get_alignment());
|
|
|
|
if (!d_rotate_2pi2) {
|
2018-07-18 18:46:08 +02:00
|
|
|
volk_free(d_rotate_pi2);
|
|
|
|
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
|
|
|
}
|
|
|
|
|
2019-09-12 15:25:10 +02:00
|
|
|
d_rotate_3pi2 = (gr_complex *) volk_malloc(d_window * sizeof(gr_complex),
|
|
|
|
volk_get_alignment());
|
|
|
|
if (!d_rotate_3pi2) {
|
2018-07-18 18:46:08 +02:00
|
|
|
volk_free(d_rotate_pi2);
|
|
|
|
volk_free(d_rotate_2pi2);
|
|
|
|
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
|
|
|
}
|
2018-07-19 01:09:07 +02:00
|
|
|
|
2018-08-09 18:29:47 +02:00
|
|
|
d_corrected = (gr_complex *)volk_malloc(d_window * sizeof(gr_complex),
|
2019-09-12 15:25:10 +02:00
|
|
|
volk_get_alignment());
|
|
|
|
if (!d_corrected) {
|
2018-07-19 01:09:07 +02:00
|
|
|
volk_free(d_rotate_pi2);
|
|
|
|
volk_free(d_rotate_2pi2);
|
|
|
|
volk_free(d_rotate_3pi2);
|
|
|
|
throw std::runtime_error("lrpt_sync: Could not allocate memory");
|
|
|
|
}
|
|
|
|
|
2018-08-09 18:29:47 +02:00
|
|
|
uint64_t asm_coded = htonll(d_asm_coded);
|
2018-07-28 20:43:56 +02:00
|
|
|
d_coded_cadu = new uint8_t[d_coded_cadu_len];
|
2018-08-02 15:17:12 +02:00
|
|
|
memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
|
|
|
|
d_received = sizeof(uint64_t);
|
2018-07-28 20:43:56 +02:00
|
|
|
|
|
|
|
message_port_register_out(pmt::mp("cadu"));
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Our virtual destructor.
|
|
|
|
*/
|
2019-09-12 15:25:10 +02:00
|
|
|
lrpt_sync_impl::~lrpt_sync_impl()
|
2018-07-18 18:46:08 +02:00
|
|
|
{
|
2019-09-12 15:25:10 +02:00
|
|
|
volk_free(d_rotate_pi2);
|
|
|
|
volk_free(d_rotate_2pi2);
|
|
|
|
volk_free(d_rotate_3pi2);
|
|
|
|
volk_free(d_corrected);
|
2018-07-19 01:09:07 +02:00
|
|
|
delete [] d_coded_cadu;
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
lrpt_sync_impl::found_sync(uint64_t reg)
|
|
|
|
{
|
2019-09-12 15:25:10 +02:00
|
|
|
return blocks::count_bits64((reg ^ d_asm_coded) & d_asm_coded_mask)
|
|
|
|
<= d_thresh;
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
|
|
|
|
{
|
|
|
|
uint32_t bits;
|
|
|
|
int multiple = noutput_items / d_window;
|
2019-09-12 15:25:10 +02:00
|
|
|
for (int i = 0; i < multiple; i++) {
|
2018-07-18 18:46:08 +02:00
|
|
|
volk_32fc_s32fc_multiply_32fc(d_rotate_pi2, in + i * d_window,
|
2018-08-09 18:29:47 +02:00
|
|
|
gr_complex(0.0, 1.0), d_window);
|
2018-07-18 18:46:08 +02:00
|
|
|
volk_32fc_s32fc_multiply_32fc(d_rotate_2pi2, in + i * d_window,
|
2018-08-09 18:29:47 +02:00
|
|
|
gr_complex(-1.0, 0.0), d_window);
|
2018-07-18 18:46:08 +02:00
|
|
|
volk_32fc_s32fc_multiply_32fc(d_rotate_3pi2, in + i * d_window,
|
2018-08-09 18:29:47 +02:00
|
|
|
gr_complex(0.0, -1.0), d_window);
|
2018-07-18 18:46:08 +02:00
|
|
|
/*
|
|
|
|
* Search for the sync pattern, rotating the QPSK constellation on
|
|
|
|
* all possible positions
|
|
|
|
*/
|
2019-09-12 15:25:10 +02:00
|
|
|
for (int j = 0; j < d_window; j++) {
|
2018-07-18 18:46:08 +02:00
|
|
|
bits = d_qpsk->decision_maker(in + i * d_window + j);
|
2018-07-28 20:43:56 +02:00
|
|
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
2018-07-18 18:46:08 +02:00
|
|
|
d_shift_reg0 = (d_shift_reg0 << 2) | bits;
|
2019-09-12 15:25:10 +02:00
|
|
|
if (found_sync(d_shift_reg0)) {
|
2018-08-09 18:29:47 +02:00
|
|
|
d_rotate = gr_complex(1.0, 0.0);
|
2018-07-18 18:46:08 +02:00
|
|
|
d_frame_sync = true;
|
2018-08-09 18:29:47 +02:00
|
|
|
uint64_t asm_coded = htonll(d_shift_reg0);
|
|
|
|
memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
|
|
|
|
return i * d_window + j + 1;
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bits = d_qpsk->decision_maker(d_rotate_pi2 + j);
|
2018-07-28 20:43:56 +02:00
|
|
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
2018-07-18 18:46:08 +02:00
|
|
|
d_shift_reg1 = (d_shift_reg1 << 2) | bits;
|
2019-09-12 15:25:10 +02:00
|
|
|
if (found_sync(d_shift_reg1)) {
|
2018-07-18 18:46:08 +02:00
|
|
|
d_rotate = gr_complex(0.0, 1.0);
|
|
|
|
d_frame_sync = true;
|
2018-08-09 18:29:47 +02:00
|
|
|
uint64_t asm_coded = htonll(d_shift_reg1);
|
|
|
|
memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
|
|
|
|
return i * d_window + j + 1;
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bits = d_qpsk->decision_maker(d_rotate_2pi2 + j);
|
2018-07-28 20:43:56 +02:00
|
|
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
2018-07-18 18:46:08 +02:00
|
|
|
d_shift_reg2 = (d_shift_reg2 << 2) | bits;
|
2019-09-12 15:25:10 +02:00
|
|
|
if (found_sync(d_shift_reg2)) {
|
2018-08-09 18:29:47 +02:00
|
|
|
d_rotate = gr_complex(-1.0, 0.0);
|
2018-07-18 18:46:08 +02:00
|
|
|
d_frame_sync = true;
|
2018-08-09 18:29:47 +02:00
|
|
|
uint64_t asm_coded = htonll(d_shift_reg2);
|
|
|
|
memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
|
|
|
|
return i * d_window + j + 1;
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bits = d_qpsk->decision_maker(d_rotate_3pi2 + j);
|
2018-07-28 20:43:56 +02:00
|
|
|
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
|
2018-07-18 18:46:08 +02:00
|
|
|
d_shift_reg3 = (d_shift_reg3 << 2) | bits;
|
2019-09-12 15:25:10 +02:00
|
|
|
if (found_sync(d_shift_reg3)) {
|
2018-07-18 18:46:08 +02:00
|
|
|
d_rotate = gr_complex(0.0, -1.0);
|
|
|
|
d_frame_sync = true;
|
2018-08-09 18:29:47 +02:00
|
|
|
uint64_t asm_coded = htonll(d_shift_reg3);
|
|
|
|
memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
|
|
|
|
return i * d_window + j + 1;
|
2018-07-18 18:46:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return noutput_items;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lrpt_sync_impl::work_sync(const gr_complex *in, int noutput_items)
|
|
|
|
{
|
2018-07-19 01:09:07 +02:00
|
|
|
uint8_t b;
|
|
|
|
int multiple = noutput_items / d_window;
|
2019-09-12 15:25:10 +02:00
|
|
|
for (int i = 0; i < multiple; i++) {
|
2018-07-19 01:09:07 +02:00
|
|
|
volk_32fc_s32fc_multiply_32fc(d_corrected, in + i * d_window,
|
|
|
|
d_rotate, d_window);
|
2019-09-12 15:25:10 +02:00
|
|
|
for (int j = 0; j < d_window; j += 4) {
|
2018-07-19 01:09:07 +02:00
|
|
|
b = 0;
|
|
|
|
b = d_qpsk->decision_maker(d_corrected + j) << 6;
|
|
|
|
b |= d_qpsk->decision_maker(d_corrected + j + 1) << 4;
|
|
|
|
b |= d_qpsk->decision_maker(d_corrected + j + 2) << 2;
|
|
|
|
b |= d_qpsk->decision_maker(d_corrected + j + 3);
|
|
|
|
|
|
|
|
d_coded_cadu[d_received++] = b;
|
2019-09-12 15:25:10 +02:00
|
|
|
if (d_received == d_coded_cadu_len) {
|
2018-08-02 15:17:12 +02:00
|
|
|
d_received = sizeof(uint64_t);
|
2018-07-19 01:09:07 +02:00
|
|
|
d_frame_sync = false;
|
2019-09-12 15:25:10 +02:00
|
|
|
message_port_pub(pmt::mp("cadu"),
|
|
|
|
pmt::make_blob(d_coded_cadu, d_coded_cadu_len));
|
2018-07-19 01:09:07 +02:00
|
|
|
return i * d_window + j + 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-18 18:46:08 +02:00
|
|
|
return noutput_items;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2019-09-12 15:25:10 +02:00
|
|
|
lrpt_sync_impl::work(int noutput_items,
|
|
|
|
gr_vector_const_void_star &input_items,
|
|
|
|
gr_vector_void_star &output_items)
|
2018-07-18 18:46:08 +02:00
|
|
|
{
|
|
|
|
const gr_complex *in = (const gr_complex *) input_items[0];
|
|
|
|
uint32_t bits;
|
2019-09-12 15:25:10 +02:00
|
|
|
if (!d_frame_sync) {
|
2018-07-18 18:46:08 +02:00
|
|
|
return work_no_sync(in, noutput_items);
|
|
|
|
}
|
|
|
|
return work_sync(in, noutput_items);
|
|
|
|
}
|
|
|
|
|
|
|
|
} /* namespace satnogs */
|
|
|
|
} /* namespace gr */
|
|
|
|
|