diff --git a/grc/satnogs_block_tree.xml b/grc/satnogs_block_tree.xml
index c7d35e8..5288ed1 100644
--- a/grc/satnogs_block_tree.xml
+++ b/grc/satnogs_block_tree.xml
@@ -17,11 +17,15 @@
AMSAT FOX
satnogs_fox_telem_mm
+
+ METOP
+ satnogs_lrpt_sync
+ satnogs_lrpt_decoder
+
satnogs_cw_matched_filter_ff
satnogs_morse_decoder
satnogs_multi_format_msg_sink
- satnogs_lrpt_sync
satnogs_iq_sink
satnogs_ogg_encoder
satnogs_ogg_source
diff --git a/include/satnogs/utils.h b/include/satnogs/utils.h
index 836c0cd..767ec17 100644
--- a/include/satnogs/utils.h
+++ b/include/satnogs/utils.h
@@ -23,12 +23,16 @@
#include
#include
+#include
namespace gr
{
namespace satnogs
{
+
+#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
/**
* Computes the Mean Absolute Percentage Error
* @param ref the reference value
diff --git a/include/satnogs/whitening.h b/include/satnogs/whitening.h
index a450016..296679c 100644
--- a/include/satnogs/whitening.h
+++ b/include/satnogs/whitening.h
@@ -41,8 +41,10 @@ namespace gr
void
reset();
- void scramble(uint8_t *out, const uint8_t *in, size_t len);
- void descramble(uint8_t *out, const uint8_t *in, size_t len);
+ void scramble(uint8_t *out, const uint8_t *in, size_t len,
+ bool msb = false);
+ void descramble(uint8_t *out, const uint8_t *in, size_t len,
+ bool msb = false);
void
scramble_one_bit_per_byte (uint8_t *out, const uint8_t *in,
diff --git a/lib/lrpt_decoder_impl.cc b/lib/lrpt_decoder_impl.cc
index 6c49d35..e7bb7bf 100644
--- a/lib/lrpt_decoder_impl.cc
+++ b/lib/lrpt_decoder_impl.cc
@@ -25,6 +25,9 @@
#include
#include "lrpt_decoder_impl.h"
#include
+#include
+
+
extern "C" {
#include
}
@@ -47,11 +50,18 @@ lrpt_decoder_impl::lrpt_decoder_impl()
: gr::block("lrpt_decoder",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0)),
- d_cadu_len(1020 + 4),
- d_coded_cadu_len(1020 * 2 + 4*2),
- d_conv_deinterl(36, 2048)
+ /*
+ * 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_cadu_len(1020 + 4 - 128),
+ d_coded_cadu_len(1020 * 2 + 4*2 - 128 * 2),
+ d_mpdu_max_len(59400),
+ d_scrambler(0x2A9, 0xFF, 7),
+ d_have_mpdu(false)
{
-
message_port_register_in(pmt::mp("cadu"));
message_port_register_out(pmt::mp("frame"));
@@ -63,11 +73,13 @@ lrpt_decoder_impl::lrpt_decoder_impl()
if(!d_vt) {
throw std::runtime_error("lrpt_decoder: Failed to init Viterbi decoder");
}
- int polys[2] = {0x79, 0x5b};
+
+ int polys[2] = {0x4f, 0x6d};
set_viterbi27_polynomial(polys);
d_cadu = new uint8_t[d_cadu_len];
d_coded_cadu_syms = new uint8_t[d_coded_cadu_len * 8];
+ d_mpdu = new uint8_t[d_mpdu_max_len];
}
@@ -79,6 +91,7 @@ lrpt_decoder_impl::~lrpt_decoder_impl ()
delete [] d_cadu;
delete [] d_coded_cadu_syms;
+ delete [] d_mpdu;
}
void
@@ -93,21 +106,68 @@ lrpt_decoder_impl::decode (pmt::pmt_t m)
init_viterbi27(d_vt, 0);
for(size_t i = 0; i < d_coded_cadu_len; i++) {
- d_coded_cadu_syms[i * 8] = ~(255 + (coded_cadu[i] >> 7));
- d_coded_cadu_syms[i * 8 + 1] = ~(255 + (coded_cadu[i] >> 6) & 0x1);
- d_coded_cadu_syms[i * 8 + 2] = ~(255 + (coded_cadu[i] >> 5) & 0x1);
- d_coded_cadu_syms[i * 8 + 3] = ~(255 + (coded_cadu[i] >> 4) & 0x1);
- d_coded_cadu_syms[i * 8 + 4] = ~(255 + (coded_cadu[i] >> 3) & 0x1);
- d_coded_cadu_syms[i * 8 + 5] = ~(255 + (coded_cadu[i] >> 2) & 0x1);
- d_coded_cadu_syms[i * 8 + 6] = ~(255 + (coded_cadu[i] >> 1) & 0x1);
- d_coded_cadu_syms[i * 8 + 7] = ~(255 + (coded_cadu[i] & 0x1));
+ d_coded_cadu_syms[i * 8] = 0xFF * (coded_cadu[i] >> 7);
+ d_coded_cadu_syms[i * 8 + 1] = 0xFF * ((coded_cadu[i] >> 6) & 0x1);
+ d_coded_cadu_syms[i * 8 + 2] = 0xFF * ((coded_cadu[i] >> 5) & 0x1);
+ d_coded_cadu_syms[i * 8 + 3] = 0xFF * ((coded_cadu[i] >> 4) & 0x1);
+ d_coded_cadu_syms[i * 8 + 4] = 0xFF * ((coded_cadu[i] >> 3) & 0x1);
+ d_coded_cadu_syms[i * 8 + 5] = 0xFF * ((coded_cadu[i] >> 2) & 0x1);
+ d_coded_cadu_syms[i * 8 + 6] = 0xFF * ((coded_cadu[i] >> 1) & 0x1);
+ d_coded_cadu_syms[i * 8 + 7] = 0xFF * ((coded_cadu[i] & 0x1));
}
+
+ /* Convolutional decoding */
update_viterbi27_blk(d_vt, d_coded_cadu_syms, d_cadu_len * 8);
chainback_viterbi27(d_vt, d_cadu, d_cadu_len * 8, 0);
- message_port_pub(pmt::mp("frame"), pmt::make_blob(d_cadu, d_cadu_len));
+
+ /* Descrambling */
+ d_scrambler.reset();
+ d_scrambler.descramble(d_cadu + 4, d_cadu + 4, d_cadu_len - 4, true);
+ decode_ccsds_packet(d_cadu + 4);
}
+void
+lrpt_decoder_impl::decode_ccsds_packet(const uint8_t *cvcdu)
+{
+ /* Check first the VCDU version and if encryption is off */
+ if( (cvcdu[0] >> 6) != 0x1) {
+ return;
+ }
+ if(cvcdu[6] != 0x0 || cvcdu[7] != 0x0) {
+ return;
+ }
+
+ /* Check if the VCDU contans data */
+ //if((cvcdu[8] >> 3) != 0x0 && (cvcdu[8] >> 3) != 0x1f) {
+ // return;
+ //}
+
+ const uint8_t *mpdu = cvcdu + 10;
+ /* Check CCSDS packet version and type */
+ //if( (mpdu[0] >> 5) != 0x0) {
+ // return;
+ // }
+
+ uint32_t vcdu_seq = 0;
+ vcdu_seq = cvcdu[2];
+ vcdu_seq = (vcdu_seq << 8) | cvcdu[3];
+ vcdu_seq = (vcdu_seq << 8) | cvcdu[4];
+
+ uint16_t hdr_ptr = 0;
+ hdr_ptr = cvcdu[8] & 0x7;
+ hdr_ptr = (hdr_ptr << 8) | cvcdu[9];
+
+ /* Try to find the start of a MPDU */
+ if(!d_have_mpdu) {
+ if(hdr_ptr != 0) {
+ return;
+ }
+ d_have_mpdu = true;
+ }
+ message_port_pub(pmt::mp("frame"), pmt::make_blob(cvcdu, d_cadu_len - 4));
+}
+
} /* namespace satnogs */
} /* namespace gr */
diff --git a/lib/lrpt_decoder_impl.h b/lib/lrpt_decoder_impl.h
index 010b0dc..378870f 100644
--- a/lib/lrpt_decoder_impl.h
+++ b/lib/lrpt_decoder_impl.h
@@ -23,6 +23,7 @@
#include
#include
+#include
namespace gr
{
@@ -39,13 +40,20 @@ public:
private:
const size_t d_cadu_len;
const size_t d_coded_cadu_len;
- convolutional_deinterleaver d_conv_deinterl;
+ const size_t d_mpdu_max_len;
+ whitening d_scrambler;
+ bool d_have_mpdu;
+
uint8_t *d_coded_cadu_syms;
uint8_t *d_cadu;
+ uint8_t *d_mpdu;
void *d_vt;
void
decode(pmt::pmt_t m);
+
+ void
+ decode_ccsds_packet(const uint8_t *cvcdu);
};
} // namespace satnogs
diff --git a/lib/lrpt_sync_impl.cc b/lib/lrpt_sync_impl.cc
index 66b72f0..4db4c2b 100644
--- a/lib/lrpt_sync_impl.cc
+++ b/lib/lrpt_sync_impl.cc
@@ -58,12 +58,18 @@ lrpt_sync_impl::lrpt_sync_impl (size_t threshold) :
*/
d_window((72 + 8)/2),
/* Each CADU has the 4 byte ASM and a VCDU of 1020 bytes*/
- d_coded_cadu_len(1020 * 2 + 4*2),
+ /*
+ * 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),
+ d_rotate(1.0, 0.0),
d_qpsk(digital::constellation_qpsk::make()),
- d_conv_deinter(36, 2048),
d_shift_reg0(0x0),
d_shift_reg1(0x0),
d_shift_reg2(0x0),
@@ -72,25 +78,29 @@ lrpt_sync_impl::lrpt_sync_impl (size_t threshold) :
set_output_multiple(d_window);
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, volk_get_alignment ());
+ d_rotate_pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
+ volk_get_alignment ());
if(!d_rotate_pi2) {
throw std::runtime_error("lrpt_sync: Could not allocate memory");
}
- d_rotate_2pi2 = (gr_complex *)volk_malloc(d_window, volk_get_alignment ());
+ d_rotate_2pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
+ volk_get_alignment ());
if(!d_rotate_2pi2) {
volk_free(d_rotate_pi2);
throw std::runtime_error("lrpt_sync: Could not allocate memory");
}
- d_rotate_3pi2 = (gr_complex *)volk_malloc(d_window, volk_get_alignment ());
+ d_rotate_3pi2 = (gr_complex *) volk_malloc (d_window * sizeof(gr_complex),
+ volk_get_alignment ());
if(!d_rotate_3pi2) {
volk_free(d_rotate_pi2);
volk_free(d_rotate_2pi2);
throw std::runtime_error("lrpt_sync: Could not allocate memory");
}
- d_corrected = (gr_complex *)volk_malloc(d_window, volk_get_alignment ());
+ d_corrected = (gr_complex *)volk_malloc(d_window * sizeof(gr_complex),
+ volk_get_alignment ());
if(!d_corrected) {
volk_free(d_rotate_pi2);
volk_free(d_rotate_2pi2);
@@ -98,7 +108,7 @@ lrpt_sync_impl::lrpt_sync_impl (size_t threshold) :
throw std::runtime_error("lrpt_sync: Could not allocate memory");
}
- uint64_t asm_coded = reverse_uint64_bytes(d_asm_coded);
+ uint64_t asm_coded = htonll(d_asm_coded);
d_coded_cadu = new uint8_t[d_coded_cadu_len];
memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
d_received = sizeof(uint64_t);
@@ -133,11 +143,11 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
int multiple = noutput_items / d_window;
for(int i = 0; i < multiple; i++) {
volk_32fc_s32fc_multiply_32fc(d_rotate_pi2, in + i * d_window,
- gr_complex(0, 1), d_window);
+ gr_complex(0.0, 1.0), d_window);
volk_32fc_s32fc_multiply_32fc(d_rotate_2pi2, in + i * d_window,
- gr_complex(-1, 0), d_window);
+ gr_complex(-1.0, 0.0), d_window);
volk_32fc_s32fc_multiply_32fc(d_rotate_3pi2, in + i * d_window,
- gr_complex(0, -1), d_window);
+ gr_complex(0.0, -1.0), d_window);
/*
* Search for the sync pattern, rotating the QPSK constellation on
* all possible positions
@@ -147,9 +157,11 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
d_shift_reg0 = (d_shift_reg0 << 2) | bits;
if(found_sync(d_shift_reg0)) {
- d_rotate = gr_complex(1.0, 0);
+ d_rotate = gr_complex(1.0, 0.0);
d_frame_sync = true;
- return i * d_window + j;
+ uint64_t asm_coded = htonll(d_shift_reg0);
+ memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
+ return i * d_window + j + 1;
}
bits = d_qpsk->decision_maker(d_rotate_pi2 + j);
@@ -158,16 +170,20 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
if(found_sync(d_shift_reg1)) {
d_rotate = gr_complex(0.0, 1.0);
d_frame_sync = true;
- return i * d_window + j;
+ uint64_t asm_coded = htonll(d_shift_reg1);
+ memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
+ return i * d_window + j + 1;
}
bits = d_qpsk->decision_maker(d_rotate_2pi2 + j);
//bits = (d_conv_deinter.decode_bit(bits >> 1) << 1) | d_conv_deinter.decode_bit(bits & 0x1);
d_shift_reg2 = (d_shift_reg2 << 2) | bits;
if(found_sync(d_shift_reg2)) {
- d_rotate = gr_complex(-1.0, 0);
+ d_rotate = gr_complex(-1.0, 0.0);
d_frame_sync = true;
- return i * d_window + j;
+ uint64_t asm_coded = htonll(d_shift_reg2);
+ memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
+ return i * d_window + j + 1;
}
bits = d_qpsk->decision_maker(d_rotate_3pi2 + j);
@@ -176,7 +192,9 @@ lrpt_sync_impl::work_no_sync(const gr_complex *in, int noutput_items)
if(found_sync(d_shift_reg3)) {
d_rotate = gr_complex(0.0, -1.0);
d_frame_sync = true;
- return i * d_window + j;
+ uint64_t asm_coded = htonll(d_shift_reg3);
+ memcpy(d_coded_cadu, &asm_coded, sizeof(uint64_t));
+ return i * d_window + j + 1;
}
}
}
@@ -200,7 +218,6 @@ lrpt_sync_impl::work_sync(const gr_complex *in, int noutput_items)
d_coded_cadu[d_received++] = b;
if(d_received == d_coded_cadu_len) {
- LOG_ERROR("frame");
d_received = sizeof(uint64_t);
d_frame_sync = false;
message_port_pub (pmt::mp ("cadu"),
diff --git a/lib/lrpt_sync_impl.h b/lib/lrpt_sync_impl.h
index 6cd0f29..516c797 100644
--- a/lib/lrpt_sync_impl.h
+++ b/lib/lrpt_sync_impl.h
@@ -44,7 +44,7 @@ public:
private:
const size_t d_thresh;
const uint64_t d_asm_coded;
- const uint64_t d_asm_coded_len;
+ const size_t d_asm_coded_len;
const uint64_t d_asm_coded_mask;
const int d_window;
const size_t d_coded_cadu_len;
@@ -52,7 +52,6 @@ private:
size_t d_received;
gr_complex d_rotate;
digital::constellation_qpsk::sptr d_qpsk;
- convolutional_deinterleaver d_conv_deinter;
uint64_t d_shift_reg0;
uint64_t d_shift_reg1;
uint64_t d_shift_reg2;
diff --git a/lib/whitening.cc b/lib/whitening.cc
index 2fff50d..b1f7733 100644
--- a/lib/whitening.cc
+++ b/lib/whitening.cc
@@ -26,97 +26,117 @@
#include
#include
-namespace gr {
- namespace satnogs {
+namespace gr
+{
+namespace satnogs
+{
- /**
- * Data whitening and de-whitening class
- * @param mask the polynomial mask
- * @param seed the initial seed
- * @param order the order of the shift register. This is equal to the
- * number of memory stages.
- */
- whitening::whitening (uint32_t mask, uint32_t seed, uint32_t order) :
- d_lfsr(mask, seed, order)
- {
+/**
+ * Data whitening and de-whitening class
+ * @param mask the polynomial mask
+ * @param seed the initial seed
+ * @param order the order of the shift register. This is equal to the
+ * number of memory stages.
+ */
+whitening::whitening (uint32_t mask, uint32_t seed, uint32_t order) :
+ d_lfsr (mask, seed, order)
+{
+}
+
+/**
+ * Resets the scrambler (or the descrambler) to the initial stage and
+ * the initial seed.
+ */
+void
+whitening::reset ()
+{
+ d_lfsr.reset ();
+}
+
+/**
+ * Performs data scrambling
+ * @param out the output buffer
+ * @param in the input buffer
+ * @param len the number of the bytes to be scrambled
+ * @param msb if set to true, the descrambler starts from the msb
+ */
+void
+whitening::scramble (uint8_t* out, const uint8_t* in, size_t len, bool msb)
+{
+ size_t i;
+ uint8_t b;
+ if(msb) {
+ for (i = 0; i < len; i++) {
+ b = d_lfsr.next_bit () << 7;
+ b |= d_lfsr.next_bit () << 6;
+ b |= d_lfsr.next_bit () << 5;
+ b |= d_lfsr.next_bit () << 4;
+ b |= d_lfsr.next_bit () << 3;
+ b |= d_lfsr.next_bit () << 2;
+ b |= d_lfsr.next_bit () << 1;
+ b |= d_lfsr.next_bit ();
+ out[i] = in[i] ^ b;
}
-
- /**
- * Resets the scrambler (or the descrambler) to the initial stage and
- * the initial seed.
- */
- void
- whitening::reset ()
- {
- d_lfsr.reset();
+ }
+ else{
+ for (i = 0; i < len; i++) {
+ b = d_lfsr.next_bit ();
+ b |= d_lfsr.next_bit () << 1;
+ b |= d_lfsr.next_bit () << 2;
+ b |= d_lfsr.next_bit () << 3;
+ b |= d_lfsr.next_bit () << 4;
+ b |= d_lfsr.next_bit () << 5;
+ b |= d_lfsr.next_bit () << 6;
+ b |= d_lfsr.next_bit () << 7;
+ out[i] = in[i] ^ b;
}
+ }
+}
- /**
- * Performs data scrambling
- * @param out the output buffer
- * @param in the input buffer
- * @param len the number of the bytes to be scrambled
- */
- void
- whitening::scramble (uint8_t* out, const uint8_t* in, size_t len)
- {
- size_t i;
- uint8_t b;
- for(i = 0; i < len; i++){
- b = d_lfsr.next_bit();
- b |= d_lfsr.next_bit() << 1;
- b |= d_lfsr.next_bit() << 2;
- b |= d_lfsr.next_bit() << 3;
- b |= d_lfsr.next_bit() << 4;
- b |= d_lfsr.next_bit() << 5;
- b |= d_lfsr.next_bit() << 6;
- b |= d_lfsr.next_bit() << 7;
- out[i] = in[i] ^ b;
- }
- }
+/**
+ * Performs data de-scrambling
+ * @param out the output buffer
+ * @param in the input buffer
+ * @param len the number of the bytes to be de-scrambled
+ * @param msb if set to true, the descrambler starts from the msb
+ */
+void
+whitening::descramble (uint8_t* out, const uint8_t* in, size_t len,
+ bool msb)
+{
+ scramble (out, in, len, msb);
+}
- /**
- * Performs data de-scrambling
- * @param out the output buffer
- * @param in the input buffer
- * @param len the number of the bytes to be de-scrambled
- */
- void
- whitening::descramble (uint8_t* out, const uint8_t* in, size_t len)
- {
- scramble(out, in, len);
- }
+/**
+ * Performs data scrambling. The input and output buffer
+ * contain one bit per byte
+ * @param out the output buffer
+ * @param in the input buffer
+ * @param bits_num the number of bits to be scrambled
+ */
+void
+whitening::scramble_one_bit_per_byte (uint8_t* out, const uint8_t* in,
+ size_t bits_num)
+{
+ size_t i;
+ for (i = 0; i < bits_num; i++) {
+ out[i] = in[i] ^ d_lfsr.next_bit ();
+ }
+}
- /**
- * Performs data scrambling. The input and output buffer
- * contain one bit per byte
- * @param out the output buffer
- * @param in the input buffer
- * @param bits_num the number of bits to be scrambled
- */
- void
- whitening::scramble_one_bit_per_byte (uint8_t* out, const uint8_t* in,
- size_t bits_num)
- {
- size_t i;
- for(i = 0; i < bits_num; i++){
- out[i] = in[i] ^ d_lfsr.next_bit();
- }
- }
+/**
+ * Performs data descrambling. The input and output buffer
+ * contain one bit per byte
+ * @param out the output buffer
+ * @param in the input buffer
+ * @param bits_num the number of bits to be descrambled
+ */
+void
+whitening::descramble_one_bit_per_byte (uint8_t* out, const uint8_t* in,
+ size_t bits_num)
+{
+ scramble_one_bit_per_byte (out, in, bits_num);
+}
- /**
- * Performs data descrambling. The input and output buffer
- * contain one bit per byte
- * @param out the output buffer
- * @param in the input buffer
- * @param bits_num the number of bits to be descrambled
- */
- void
- whitening::descramble_one_bit_per_byte (uint8_t* out, const uint8_t* in,
- size_t bits_num)
- {
- scramble_one_bit_per_byte(out, in, bits_num);
- }
-
- } /* namespace satnogs */
+} /* namespace satnogs */
} /* namespace gr */