diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b396aae..ff00ce5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,7 @@
image: debian:latest
before_script:
- - apt-get update -qq && apt-get install -y -qq gnuradio-dev libcppunit-dev libpng++-dev libvorbis-dev libnova-dev cmake swig pkg-config build-essential
+ - apt-get update -qq && apt-get install -y -qq gnuradio-dev libcppunit-dev libpng++-dev libvorbis-dev cmake swig pkg-config build-essential git
test:
script:
diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt
index 2001a8e..bdd10a2 100644
--- a/grc/CMakeLists.txt
+++ b/grc/CMakeLists.txt
@@ -51,6 +51,7 @@ list(APPEND enabled_blocks
satnogs_quad_demod_filter_ff.xml
satnogs_ogg_source.xml
satnogs_noaa_apt_sink.xml
+ satnogs_whitening.xml
)
if(${INCLUDE_DEBUG_BLOCKS})
diff --git a/grc/satnogs_block_tree.xml b/grc/satnogs_block_tree.xml
index 5288ed1..05efb7d 100644
--- a/grc/satnogs_block_tree.xml
+++ b/grc/satnogs_block_tree.xml
@@ -41,4 +41,5 @@
satnogs_quad_demod_filter_ff
satnogs_ccsds_rs_decoder_mm
satnogs_decoder_8b10b
+ variable_whitening
\ No newline at end of file
diff --git a/grc/satnogs_whitening.xml b/grc/satnogs_whitening.xml
new file mode 100644
index 0000000..d166aea
--- /dev/null
+++ b/grc/satnogs_whitening.xml
@@ -0,0 +1,35 @@
+
+
+ Whitening
+ variable_whitening
+ import satnogs
+ self.$(id) = $(id) = satnogs.whitening_make($mask, $seed, $order)
+ satnogs.whitening_make($mask, $seed, $order)
+
+
+ Ignore Me
+ value
+ 'ok'
+ raw
+ all
+
+
+
+ Mask
+ mask
+ int
+
+
+
+ Seed
+ seed
+ int
+
+
+
+ Order
+ order
+ int
+
+
+
diff --git a/include/satnogs/frame_acquisition.h b/include/satnogs/frame_acquisition.h
index c1c7368..7a7b57f 100644
--- a/include/satnogs/frame_acquisition.h
+++ b/include/satnogs/frame_acquisition.h
@@ -22,6 +22,7 @@
#define INCLUDED_SATNOGS_FRAME_ACQUISITION_H
#include
+#include
#include
namespace gr
@@ -39,19 +40,42 @@ class SATNOGS_API frame_acquisition : virtual public gr::sync_block
public:
typedef boost::shared_ptr sptr;
- /*!
- * \brief Return a shared_ptr to a new instance of satnogs::frame_acquisition.
- *
- * To avoid accidental use of raw pointers, satnogs::frame_acquisition's
- * constructor is in a private implementation
- * class. satnogs::frame_acquisition::make is the public interface for
- * creating new instances.
- */
+ typedef enum {
+ CRC_NONE = 0,
+ CRC16,
+ CRC32
+ } checksum_t;
+
+
static sptr
- make (const std::vector& preamble,
- size_t preamble_threshold,
- const std::vector& sync,
- size_t sync_threshold);
+ make_generic_var_len (const std::vector& preamble,
+ size_t preamble_threshold,
+ const std::vector& sync,
+ size_t sync_threshold,
+ size_t frame_size_len = 1,
+ checksum_t crc = CRC_NONE,
+ whitening::sptr descrambler = nullptr,
+ size_t max_frame_len = 2048);
+
+ static sptr
+ make_generic_const_len(const std::vector& preamble,
+ size_t preamble_threshold,
+ const std::vector& sync,
+ size_t sync_threshold,
+ size_t frame_len = 1,
+ checksum_t crc = CRC_NONE,
+ whitening::sptr descrambler = nullptr,
+ size_t max_frame_len = 2048);
+
+ static sptr
+ make_golay24_var_len (const std::vector& preamble,
+ size_t preamble_threshold,
+ const std::vector& sync,
+ size_t sync_threshold,
+ checksum_t crc = CRC_NONE,
+ whitening::sptr descrambler = nullptr,
+ size_t max_frame_len = 2048);
+
};
} // namespace satnogs
diff --git a/include/satnogs/whitening.h b/include/satnogs/whitening.h
index 296679c..f54c109 100644
--- a/include/satnogs/whitening.h
+++ b/include/satnogs/whitening.h
@@ -23,41 +23,52 @@
#include
#include
+#include
namespace gr
{
- namespace satnogs
- {
+namespace satnogs
+{
- /*!
- * \brief Performs data whitening and de-whitening
- *
- */
- class SATNOGS_API whitening
- {
- public:
- whitening (uint32_t mask, uint32_t seed, uint32_t order);
+/*!
+ * \brief Performs data whitening and de-whitening
+ *
+ */
+class SATNOGS_API whitening
+{
+public:
+ static int base_unique_id;
- void
- reset();
+ int
+ unique_id ();
- 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);
+ typedef boost::shared_ptr sptr;
- void
- scramble_one_bit_per_byte (uint8_t *out, const uint8_t *in,
- size_t bits_num);
- void
- descramble_one_bit_per_byte (uint8_t *out, const uint8_t *in,
- size_t bits_num);
+ static sptr
+ make(uint32_t mask, uint32_t seed, uint32_t order);
- private:
- digital::lfsr d_lfsr;
- };
+ whitening (uint32_t mask, uint32_t seed, uint32_t order);
- } // namespace satnogs
+ void
+ reset ();
+
+ 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, size_t bits_num);
+ void
+ descramble_one_bit_per_byte (uint8_t *out, const uint8_t *in,
+ size_t bits_num);
+
+private:
+ digital::lfsr d_lfsr;
+int d_id;
+};
+
+} // namespace satnogs
} // namespace gr
#endif /* INCLUDED_SATNOGS_WHITENING_H */
diff --git a/lib/frame_acquisition_impl.cc b/lib/frame_acquisition_impl.cc
index 10d3505..1383ed9 100644
--- a/lib/frame_acquisition_impl.cc
+++ b/lib/frame_acquisition_impl.cc
@@ -23,36 +23,96 @@
#endif
#include
+
#include "frame_acquisition_impl.h"
+#include
+
namespace gr
{
namespace satnogs
{
frame_acquisition::sptr
-frame_acquisition::make (const std::vector& preamble,
- size_t preamble_threshold,
- const std::vector& sync,
- size_t sync_threshold)
+frame_acquisition::make_generic_var_len (const std::vector& preamble,
+ size_t preamble_threshold,
+ const std::vector& sync,
+ size_t sync_threshold,
+ size_t frame_size_len,
+ checksum_t crc,
+ whitening::sptr descrambler,
+ size_t max_frame_len)
{
return gnuradio::get_initial_sptr (
- new frame_acquisition_impl (preamble, preamble_threshold, sync,
- sync_threshold));
+ new frame_acquisition_impl (frame_acquisition_impl::GENERIC_VAR_FRAME_LEN,
+ preamble,
+ preamble_threshold, sync, sync_threshold,
+ frame_size_len, 0, crc, descrambler,
+ max_frame_len));
}
-frame_acquisition_impl::frame_acquisition_impl (
- const std::vector& preamble, size_t preamble_threshold,
- const std::vector& sync, size_t sync_threshold) :
+frame_acquisition::sptr
+frame_acquisition::make_generic_const_len (const std::vector& preamble,
+ size_t preamble_threshold,
+ const std::vector& sync,
+ size_t sync_threshold,
+ size_t frame_len, checksum_t crc,
+ whitening::sptr descrambler,
+ size_t max_frame_len)
+{
+ return gnuradio::get_initial_sptr (
+ new frame_acquisition_impl (frame_acquisition_impl::GENERIC_CONSTANT_FRAME_LEN,
+ preamble,
+ preamble_threshold, sync, sync_threshold,
+ 0, frame_len, crc, descrambler,
+ max_frame_len));
+}
+
+frame_acquisition::sptr
+frame_acquisition::make_golay24_var_len (const std::vector& preamble,
+ size_t preamble_threshold,
+ const std::vector& sync,
+ size_t sync_threshold, checksum_t crc,
+ whitening::sptr descrambler,
+ size_t max_frame_len)
+{
+ return gnuradio::get_initial_sptr (
+ new frame_acquisition_impl (frame_acquisition_impl::GOLAY24_CODED_FRAME_LEN,
+ preamble,
+ preamble_threshold, sync, sync_threshold,
+ 0, 0, crc, descrambler,
+ max_frame_len));
+}
+
+frame_acquisition_impl::frame_acquisition_impl (variant_t variant,
+ const std::vector& preamble,
+ size_t preamble_threshold,
+ const std::vector& sync,
+ size_t sync_threshold,
+ size_t frame_size_len,
+ size_t frame_len,
+ checksum_t crc,
+ whitening::sptr descrambler,
+ size_t max_frame_len) :
gr::sync_block ("frame_acquisition",
gr::io_signature::make (1, 1, sizeof(uint8_t)),
gr::io_signature::make (0, 0, 0)),
+ d_variant(variant),
d_preamble(preamble.size() * 8),
+ d_preamble_shift_reg(preamble.size() * 8),
d_preamble_len(preamble.size() * 8),
d_preamble_thrsh(preamble_threshold),
d_sync(sync.size() * 8),
+ d_sync_shift_reg(sync.size() * 8),
d_sync_len(sync.size() * 8),
- d_sync_thrsh(sync_threshold)
+ d_sync_thrsh(sync_threshold),
+ d_state(SEARCHING),
+ d_cnt(0),
+ d_frame_size_field_len(frame_size_len),
+ d_frame_len(frame_len),
+ d_max_frame_len(max_frame_len),
+ d_crc(crc),
+ d_whitening(descrambler)
{
set_output_multiple(8);
for(uint8_t b : preamble) {
@@ -77,6 +137,45 @@ frame_acquisition_impl::frame_acquisition_impl (
d_sync <<= ((b >> 1) & 0x1);
d_sync <<= (b & 0x1);
}
+
+ /* Parameters checking */
+ if (max_frame_len == 0) {
+ throw std::invalid_argument (
+ "The maximum frame size should be at least 1 byte");
+ }
+
+ if(d_sync_len < 8) {
+ throw std::invalid_argument("SYNC word should be at least 8 bits");
+ }
+
+ if(d_preamble_len < 8) {
+ throw std::invalid_argument("Preamble should be at least 8 bits");
+ }
+
+ if (d_preamble_len < 2 * d_preamble_thrsh) {
+ throw std::invalid_argument (
+ "Too many error bits are allowed for the preamble."
+ "Consider lowering the threshold");
+ }
+
+ if (d_sync_len < 2 * d_sync_thrsh) {
+ throw std::invalid_argument (
+ "Too many error bits are allowed for the sync word. "
+ "Consider lowering the threshold");
+ }
+
+ if (d_frame_size_field_len > 4) {
+ throw std::invalid_argument ("Frame length field can be up to 4 bytes");
+ }
+
+ if (d_frame_size_field_len == 0) {
+ throw std::invalid_argument ("Frame length field cannot be 0");
+ }
+
+ d_pdu = new uint8_t[max_frame_len];
+
+ /* Register the PMT message queue */
+ message_port_register_out(pmt::mp("out"));
}
/*
@@ -84,6 +183,7 @@ frame_acquisition_impl::frame_acquisition_impl (
*/
frame_acquisition_impl::~frame_acquisition_impl ()
{
+ delete [] d_pdu;
}
@@ -95,10 +195,196 @@ frame_acquisition_impl::work (int noutput_items,
{
const uint8_t *in = (const uint8_t *) input_items[0];
- // Do <+signal processing+>
+ switch(d_state)
+ {
+ case SEARCHING:
+ return searching_preamble(in, noutput_items);
+ case SEARCHING_SYNC:
+ return searching_sync(in, noutput_items);
+ case DECODING_GENERIC_FRAME_LEN:
+ return dec_generic_frame_len(in, noutput_items);
+ case DECODING_GOLAY24_FRAME_LEN:
+ return dec_golay24_frame_len(in, noutput_items);
+ case DECODING_PAYLOAD:
+ return decoding(in, noutput_items);
+ default:
+ return noutput_items;
+ }
+}
- // Tell runtime system how many output items we produced.
- return noutput_items;
+int
+frame_acquisition_impl::searching_preamble (const uint8_t* in, int len)
+{
+ for(int i = 0; i < len; i++) {
+ d_preamble_shift_reg <<= in[i];
+ shift_reg tmp = d_preamble_shift_reg ^ d_preamble;
+ if(tmp.count() <= d_preamble_thrsh) {
+ d_state = SEARCHING_SYNC;
+ d_cnt = 0;
+ return i+1;
+ }
+ }
+ return len;
+}
+
+int
+frame_acquisition_impl::searching_sync (const uint8_t* in, int len)
+{
+ for (int i = 0; i < len; i++) {
+ d_sync_shift_reg <<= in[i];
+ shift_reg tmp = d_sync_shift_reg ^ d_sync;
+ d_cnt++;
+ if (tmp.count () <= d_sync_thrsh) {
+ switch(d_variant) {
+ case GENERIC_VAR_FRAME_LEN:
+ d_state = DECODING_GENERIC_FRAME_LEN;
+ break;
+ case GENERIC_CONSTANT_FRAME_LEN:
+ d_state = DECODING_GENERIC_FRAME_LEN;
+ break;
+ }
+ d_cnt = 0;
+ return i + 1;
+ }
+
+ /* The sync word should be available by now */
+ if(d_cnt > d_preamble_len * 2 + d_sync_len) {
+ reset();
+ return i + 1;
+ }
+ }
+ return len;
+}
+
+int
+frame_acquisition_impl::dec_generic_frame_len (const uint8_t* in, int len)
+{
+ const int s = std::min(len / 8, (int) d_frame_size_field_len);
+ for(int i = 0; i < s; i++) {
+ uint8_t b = 0x0;
+ b |= in[i * 8] << 7;
+ b |= in[i * 8 + 1] << 6;
+ b |= in[i * 8 + 2] << 5;
+ b |= in[i * 8 + 3] << 4;
+ b |= in[i * 8 + 4] << 3;
+ b |= in[i * 8 + 5] << 2;
+ b |= in[i * 8 + 6] << 1;
+ b |= in[i * 8 + 7];
+ d_frame_len <<= 8;
+ d_frame_len |= b;
+ d_cnt++;
+ if(d_cnt == d_frame_size_field_len) {
+
+ /* Most of the available modems apply whitening on the frame length too */
+ if(d_whitening) {
+ uint32_t descrambled = 0x0;
+ d_whitening->descramble((uint8_t *)&descrambled,
+ (const uint8_t *)&d_frame_len,
+ d_frame_size_field_len, true);
+ d_frame_len = descrambled;
+ }
+ if(d_frame_len < d_max_frame_len) {
+ d_state = DECODING_PAYLOAD;
+ }
+ else{
+ reset();
+ return (i + 1) * 8;
+ }
+ d_cnt = 0;
+ return (i + 1) * 8;
+ }
+ }
+ return s * 8;
+}
+
+int
+frame_acquisition_impl::dec_golay24_frame_len (const uint8_t* in, int len)
+{
+ /* Golay24 needs 3 bytes to decode */
+ const int s = std::min(len / 8, 3);
+ for(int i = 0; i < s; i++) {
+ uint8_t b = 0x0;
+ b |= in[i * 8] << 7;
+ b |= in[i * 8 + 1] << 6;
+ b |= in[i * 8 + 2] << 5;
+ b |= in[i * 8 + 3] << 4;
+ b |= in[i * 8 + 4] << 3;
+ b |= in[i * 8 + 5] << 2;
+ b |= in[i * 8 + 6] << 1;
+ b |= in[i * 8 + 7];
+ d_frame_len <<= 8;
+ d_frame_len |= b;
+ d_cnt++;
+
+ /* Try to decode the frame length */
+ if (d_cnt == 3) {
+ if(d_whitening) {
+ uint32_t descrambled = 0x0;
+ d_whitening->descramble((uint8_t *)&descrambled,
+ (const uint8_t *)&d_frame_len, 3, true);
+ d_frame_len = descrambled;
+ }
+ golay24 g = golay24 ();
+ uint16_t tmp = 0;
+ if (g.decode24 (&tmp, d_frame_len)) {
+ d_frame_len = tmp;
+ /* Check if the payload can fit in the buffer */
+ if(d_frame_len > d_max_frame_len) {
+ reset();
+ return (i + 1) * 8;
+ }
+ else{
+ d_state = DECODING_PAYLOAD;
+ }
+ }
+ else {
+ reset ();
+ return (i + 1) * 8;
+ }
+ d_cnt = 0;
+ return (i + 1) * 8;
+ }
+ }
+ return s * 8;
+}
+
+int
+frame_acquisition_impl::decoding (const uint8_t* in, int len)
+{
+ const int s = len / 8;
+ for(int i = 0; i < s; i++) {
+ uint8_t b = 0x0;
+ b |= in[i * 8] << 7;
+ b |= in[i * 8 + 1] << 6;
+ b |= in[i * 8 + 2] << 5;
+ b |= in[i * 8 + 3] << 4;
+ b |= in[i * 8 + 4] << 3;
+ b |= in[i * 8 + 5] << 2;
+ b |= in[i * 8 + 6] << 1;
+ b |= in[i * 8 + 7];
+ d_pdu[d_cnt++] = b;
+ if(d_cnt == d_frame_len) {
+ if(d_whitening) {
+ d_whitening->descramble(d_pdu, d_pdu, d_frame_len, true);
+ }
+ /* TODO */
+ reset();
+ return (i+1) * 8;
+ }
+ }
+ return len;
+}
+
+void
+frame_acquisition_impl::reset ()
+{
+ if(d_whitening) {
+ d_whitening->reset();
+ }
+ d_cnt = 0;
+ d_state = SEARCHING;
+ d_preamble_shift_reg.reset();
+ d_sync_shift_reg.reset();
}
} /* namespace satnogs */
diff --git a/lib/frame_acquisition_impl.h b/lib/frame_acquisition_impl.h
index afe1f71..40aca9c 100644
--- a/lib/frame_acquisition_impl.h
+++ b/lib/frame_acquisition_impl.h
@@ -33,10 +33,23 @@ class frame_acquisition_impl : public frame_acquisition
{
public:
- frame_acquisition_impl (const std::vector& preamble,
+ typedef enum {
+ GENERIC_VAR_FRAME_LEN = 0,
+ GENERIC_CONSTANT_FRAME_LEN,
+ GOLAY24_CODED_FRAME_LEN
+ } variant_t;
+
+ frame_acquisition_impl (variant_t variant,
+ const std::vector& preamble,
size_t preamble_threshold,
const std::vector& sync,
- size_t sync_threshold);
+ size_t sync_threshold,
+ size_t frame_size_len,
+ size_t frame_len,
+ checksum_t crc,
+ whitening::sptr descrambler,
+ size_t max_frame_len);
+
~frame_acquisition_impl ();
// Where all the action really happens
@@ -45,12 +58,53 @@ public:
gr_vector_void_star &output_items);
private:
+ /**
+ * Decoding FSM
+ */
+ typedef enum
+ {
+ SEARCHING, //!< when searching for the start of the preamble
+ SEARCHING_SYNC,
+ DECODING_GENERIC_FRAME_LEN,
+ DECODING_GOLAY24_FRAME_LEN,
+ DECODING_PAYLOAD
+ } decoding_state_t;
+
+ const variant_t d_variant;
shift_reg d_preamble;
+ shift_reg d_preamble_shift_reg;
const size_t d_preamble_len;
const size_t d_preamble_thrsh;
shift_reg d_sync;
+ shift_reg d_sync_shift_reg;
const size_t d_sync_len;
const size_t d_sync_thrsh;
+ decoding_state_t d_state;
+ uint32_t d_cnt;
+ const uint32_t d_frame_size_field_len;
+ uint32_t d_frame_len;
+ const uint32_t d_max_frame_len;
+ const checksum_t d_crc;
+ whitening::sptr d_whitening;
+ uint8_t *d_pdu;
+
+
+ int
+ searching_preamble(const uint8_t *in, int len);
+
+ int
+ searching_sync(const uint8_t *in, int len);
+
+ int dec_generic_frame_len(const uint8_t *in, int len);
+
+
+ int dec_golay24_frame_len(const uint8_t *in, int len);
+
+ int
+ decoding(const uint8_t *in, int len);
+
+ void
+ reset();
};
} // namespace satnogs
diff --git a/lib/whitening.cc b/lib/whitening.cc
index b1f7733..88488f8 100644
--- a/lib/whitening.cc
+++ b/lib/whitening.cc
@@ -31,6 +31,23 @@ namespace gr
namespace satnogs
{
+int whitening::base_unique_id = 1;
+
+
+/**
+ * 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::sptr
+whitening::make (uint32_t mask, uint32_t seed, uint32_t order)
+{
+ return whitening::sptr(new whitening(mask, seed, order));
+}
+
+
/**
* Data whitening and de-whitening class
* @param mask the polynomial mask
@@ -39,8 +56,16 @@ namespace satnogs
* number of memory stages.
*/
whitening::whitening (uint32_t mask, uint32_t seed, uint32_t order) :
- d_lfsr (mask, seed, order)
+ d_lfsr (mask, seed, order),
+ d_id(0)
{
+ d_id = base_unique_id++;
+}
+
+int
+whitening::unique_id ()
+{
+ return d_id;
}
/**