Use the shift register approach for the DUV decoder

This commit is contained in:
Manolis Surligas 2019-09-02 20:20:21 +03:00
parent c5f376929c
commit c9f685d1c1
6 changed files with 205 additions and 83 deletions

View File

@ -24,6 +24,7 @@
#include <satnogs/api.h>
#include <satnogs/decoder.h>
#include <string>
#include <deque>
namespace gr
{
@ -37,6 +38,13 @@ namespace satnogs
class SATNOGS_API amsat_duv_decoder : public decoder
{
public:
static const size_t
amsat_fox_duv_frame_size;
static const uint8_t
amsat_fox_spacecraft_id[];
static decoder::decoder_sptr
make(const std::string& control_symbol, size_t max_frame_len = 96);
@ -52,7 +60,7 @@ public:
private:
typedef enum
{
IN_SYNC, DECODING
SEARCH_SYNC, DECODING
} d_state_t;
size_t d_erasure_cnt;
@ -68,12 +76,17 @@ private:
uint8_t *d_8b_words;
int *d_erasures_indexes;
d_state_t d_state;
size_t d_bitstream_idx;
std::deque<uint8_t> d_bitstream;
bool
set_access_code (const std::string &control_symbol);
void
process_10b (uint16_t word, int write_pos);
process_10b (uint16_t word, size_t write_pos);
inline uint16_t
pack_10b_word(size_t idx);
int d_lookup_8b10b[2][256] =
{

View File

@ -21,38 +21,47 @@
#ifndef INCLUDE_SATNOGS_METADATA_H_
#define INCLUDE_SATNOGS_METADATA_H_
#include <satnogs/api.h>
#include <string>
#include <pmt/pmt.h>
#include <json/json.h>
#include <cstdint>
namespace gr {
namespace satnogs {
class metadata
class SATNOGS_API metadata
{
public:
typedef enum {
PDU,
typedef enum key{
PDU = 0,
CRC_VALID,
FREQ_OFFSET,
CORRECTED_BITS,
TIME,
SAMPLE_START,
SAMPLE_CNT,
SYMBOL_ERASURES
SYMBOL_ERASURES,
KEYS_NUM
} key_t;
static std::string
value(const key_t& k);
static std::string
keys();
static std::string
time_iso8601();
static void
add_time_iso8601(pmt::pmt_t &m);
static void
add_pdu(pmt::pmt_t &m, const uint8_t *in, size_t len);
static void
add_crc_valid(pmt::pmt_t &m, bool valid);

View File

@ -28,7 +28,7 @@
#include <gnuradio/blocks/count_bits.h>
extern "C" {
#include <fec.h>
#include <fec.h>
}
namespace gr
@ -36,6 +36,21 @@ namespace gr
namespace satnogs
{
/**
* Actual frame size without RS padding and parity.
* 6 bytes are header, 58 payload
*/
const size_t amsat_duv_decoder::amsat_fox_duv_frame_size = 6 + 58;
const uint8_t amsat_duv_decoder::amsat_fox_spacecraft_id[]
{
0x1 /* FOX-1A */,
0x2 /* FOX-1B */,
0x3 /* FOX-1C */,
0x4 /* FOX-1D */,
0x5 /* FOX-1E */
};
/**
* Creates a shared pointer to a amsat_duv_decoder object
* @param control_symbol the control symbol indicating the start of a frame
@ -43,11 +58,11 @@ namespace satnogs
* @return a shared pointer to a amsat_duv_decoder object
*/
decoder::decoder_sptr
amsat_duv_decoder::make (const std::string& control_symbol,
amsat_duv_decoder::make (const std::string &control_symbol,
size_t max_frame_len)
{
return decoder::decoder_sptr(new amsat_duv_decoder(control_symbol,
max_frame_len));
return decoder::decoder_sptr (
new amsat_duv_decoder (control_symbol, max_frame_len));
}
/**
@ -56,7 +71,7 @@ amsat_duv_decoder::make (const std::string& control_symbol,
* @param control_symbol the control symbol indicating the start of a frame
* @param max_frame_len the maximum frame length
*/
amsat_duv_decoder::amsat_duv_decoder (const std::string& control_symbol,
amsat_duv_decoder::amsat_duv_decoder (const std::string &control_symbol,
size_t max_frame_len) :
decoder (1, max_frame_len),
d_erasure_cnt (0),
@ -68,7 +83,8 @@ amsat_duv_decoder::amsat_duv_decoder (const std::string& control_symbol,
d_nwrong (0),
d_nwrong_neg (0),
d_word_cnt (0),
d_state (IN_SYNC)
d_bitstream_idx (0),
d_state (SEARCH_SYNC)
{
d_8b_words = new uint8_t[max_frame_len];
d_erasures_indexes = new int[max_frame_len];
@ -103,7 +119,7 @@ amsat_duv_decoder::~amsat_duv_decoder ()
}
void
amsat_duv_decoder::process_10b (uint16_t word, int write_pos)
amsat_duv_decoder::process_10b (uint16_t word, size_t write_pos)
{
uint16_t diff_bits = 0;
uint8_t min_pos = 0;
@ -147,81 +163,139 @@ amsat_duv_decoder::process_10b (uint16_t word, int write_pos)
}
}
static inline uint16_t
pack_10b_word (const uint8_t *in)
inline uint16_t
amsat_duv_decoder::pack_10b_word (size_t idx)
{
return (((uint16_t) in[0] & 0x1) << 9) | (((uint16_t) in[1] & 0x1) << 8)
| (((uint16_t) in[2] & 0x1) << 7) | (((uint16_t) in[3] & 0x1) << 6)
| (((uint16_t) in[4] & 0x1) << 5) | (((uint16_t) in[5] & 0x1) << 4)
| (((uint16_t) in[6] & 0x1) << 3) | (((uint16_t) in[7] & 0x1) << 2)
| (((uint16_t) in[8] & 0x1) << 1) | (in[9] & 0x1);
return (((uint16_t) d_bitstream[idx] & 0x1) << 9)
| (((uint16_t) d_bitstream[idx + 1] & 0x1) << 8)
| (((uint16_t) d_bitstream[idx + 2] & 0x1) << 7)
| (((uint16_t) d_bitstream[idx + 3] & 0x1) << 6)
| (((uint16_t) d_bitstream[idx + 4] & 0x1) << 5)
| (((uint16_t) d_bitstream[idx + 5] & 0x1) << 4)
| (((uint16_t) d_bitstream[idx + 6] & 0x1) << 3)
| (((uint16_t) d_bitstream[idx + 7] & 0x1) << 2)
| (((uint16_t) d_bitstream[idx + 8] & 0x1) << 1)
| (d_bitstream[idx + 9] & 0x1);
}
static inline bool
is_spacecraft_valid (uint8_t id)
{
for (size_t i = 0; i < sizeof(amsat_duv_decoder::amsat_fox_spacecraft_id);
i++) {
if (amsat_duv_decoder::amsat_fox_spacecraft_id[i] == id) {
return true;
}
}
return false;
}
decoder_status_t
amsat_duv_decoder::decode (const void *in, int len)
{
const uint8_t *input = (const uint8_t *) in;
const uint8_t *input = (const uint8_t*) in;
decoder_status_t status;
int ret;
uint16_t word;
size_t available;
/* Search for the Comma symbol */
if (d_state == IN_SYNC) {
for (int i = 0; i < len; i++) {
d_data_reg = (d_data_reg << 1) | (input[i] & 0x1);
d_wrong_bits = (d_data_reg ^ d_control_symbol_pos) & 0x3FF;
d_wrong_bits_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF;
d_nwrong = gr::blocks::count_bits16 (d_wrong_bits);
d_nwrong_neg = gr::blocks::count_bits16 (d_wrong_bits_neg);
/* we found the controls symbol */
if ((d_nwrong == 0) || (d_nwrong_neg == 0)) {
d_erasure_cnt = 0;
d_word_cnt = 0;
d_state = DECODING;
status.consumed = i + 1;
return status;
}
}
status.consumed = len;
return status;
/* Due to internal buffering we consume all the availabele symbols */
for (int i = 0; i < len; i++) {
d_bitstream.push_back (input[i]);
}
status.consumed = len;
/*
* From now one, we have a SYNC so we process the data
* in chunks of 10 bits
*/
for (int i = 0; i < len / 10; i++) {
word = pack_10b_word (&input[i * 10]);
/* Revert 10b to 8b and accumulate! */
process_10b (word, d_word_cnt);
d_word_cnt++;
if (d_word_cnt == max_frame_len()) {
d_state = IN_SYNC;
if (d_erasure_cnt > 0) {
ret = decode_rs_8(d_8b_words, d_erasures_indexes, d_erasure_cnt,
255 - max_frame_len());
}
else{
ret = decode_rs_8(d_8b_words, NULL, 0, 255 - max_frame_len());
}
if(ret > -1) {
status.data = pmt::dict_add(status.data,
pmt::mp(metadata::value(metadata::PDU)),
pmt::make_blob(d_8b_words, 223));
metadata::add_symbol_erasures(status.data, d_erasure_cnt);
metadata::add_corrected_bits(status.data, ret);
status.decode_success = true;
}
status.consumed = (i + 1) * 10;
while (1) {
bool cont = false;
if(d_bitstream.size() < 11) {
return status;
}
switch (d_state)
{
case SEARCH_SYNC:
for (size_t i = 0; i < d_bitstream.size (); i++) {
d_data_reg = (d_data_reg << 1) | (d_bitstream[i] & 0x1);
d_wrong_bits = (d_data_reg ^ d_control_symbol_pos) & 0x3FF;
d_wrong_bits_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF;
d_nwrong = gr::blocks::count_bits16 (d_wrong_bits);
d_nwrong_neg = gr::blocks::count_bits16 (d_wrong_bits_neg);
/* we found the controls symbol */
if ((d_nwrong == 0) || (d_nwrong_neg == 0)) {
d_erasure_cnt = 0;
d_word_cnt = 0;
d_state = DECODING;
if(i > 10) {
d_bitstream_idx = 9;
d_bitstream.erase (d_bitstream.begin (),
d_bitstream.begin () + i + 1 - 9);
}
else {
d_bitstream_idx = i;
d_bitstream.pop_front();
}
return status;
}
}
/* No SYNC found on the entire buffer. Clear it and return */
d_bitstream.clear ();
return status;
case DECODING:
available = d_bitstream.size() - d_bitstream_idx;
if(available < 10) {
return status;
}
/*
* From now one, we have a SYNC so we process the data
* in chunks of 10 bits
*/
for (size_t i = 0; i < available / 10; i++, d_bitstream_idx += 10) {
word = pack_10b_word (d_bitstream_idx);
/* Revert 10b to 8b and accumulate! */
process_10b (word, d_word_cnt);
d_word_cnt++;
if (d_word_cnt == max_frame_len ()) {
d_state = SEARCH_SYNC;
d_data_reg = 0;
if (d_erasure_cnt > 0) {
ret = decode_rs_8 (d_8b_words, d_erasures_indexes, d_erasure_cnt,
255 - max_frame_len ());
}
else {
ret = decode_rs_8 (d_8b_words, NULL, 0, 255 - max_frame_len ());
}
if (ret > -1) {
uint8_t fox_id = d_8b_words[0] & 0x7;
if (is_spacecraft_valid (fox_id)) {
metadata::add_pdu (status.data, d_8b_words,
amsat_fox_duv_frame_size);
metadata::add_symbol_erasures (status.data, d_erasure_cnt);
metadata::add_corrected_bits (status.data, ret);
metadata::add_time_iso8601 (status.data);
status.decode_success = true;
d_bitstream.erase (d_bitstream.begin (),
d_bitstream.begin () + (i + 1) * 10 + 1);
return status;
}
}
/* Frame could not be decoded. Retry to sync */
cont = true;
break;
}
}
if(cont) {
continue;
}
return status;
default:
throw std::invalid_argument (
"amsat_duv_decoder: Invalid decoding state");
}
}
status.consumed = (len / 10) * 10;
return status;
}
void
@ -229,10 +303,11 @@ amsat_duv_decoder::reset ()
{
d_erasure_cnt = 0;
d_word_cnt = 0;
d_state = IN_SYNC;
d_state = SEARCH_SYNC;
d_bitstream.clear ();
d_bitstream_idx = 0;
}
} /* namespace satnogs */
} /* namespace gr */

View File

@ -270,9 +270,7 @@ ax25_decoder::enter_frame_end (decoder_status_t& status)
* Using this field also try to correct up to 2 error bits
*/
if (frame_check ()) {
status.data = pmt::dict_add (
status.data, pmt::mp (metadata::value (metadata::PDU)),
pmt::make_blob (d_frame_buffer, d_received_bytes - sizeof(uint16_t)));
metadata::add_pdu(status.data, d_frame_buffer, d_received_bytes - sizeof(uint16_t));
metadata::add_time_iso8601(status.data);
metadata::add_crc_valid(status.data, true);
metadata::add_sample_start(status.data, d_frame_start);
@ -281,9 +279,7 @@ ax25_decoder::enter_frame_end (decoder_status_t& status)
return true;
}
else if(!d_crc_check){
status.data = pmt::dict_add (
status.data, pmt::mp (metadata::value (metadata::PDU)),
pmt::make_blob (d_frame_buffer, d_received_bytes - sizeof(uint16_t)));
metadata::add_pdu(status.data, d_frame_buffer, d_received_bytes - sizeof(uint16_t));
metadata::add_time_iso8601(status.data);
metadata::add_crc_valid(status.data, false);
status.decode_success = true;

View File

@ -28,6 +28,25 @@ namespace gr {
namespace satnogs {
std::string
metadata::keys()
{
std::string s = "[";
for(size_t i = 0; i < KEYS_NUM - 1; i++) {
s.append(value((key_t) i));
s.append(", ");
}
s.append(value((key_t)(KEYS_NUM - 1)));
s.append("]");
return s;
}
/**
* Return the string representation of the @a k.
* This string can be
* @param k the key enumeration
* @return string corresponding to the key @a k value
*/
std::string
metadata::value(const key_t& k)
{
@ -46,6 +65,8 @@ metadata::value(const key_t& k)
return "sample_start";
case SAMPLE_CNT:
return "sample_cnt";
case SYMBOL_ERASURES:
return "symbol_erasures";
default:
throw std::invalid_argument("metadata: invalid key");
}
@ -75,6 +96,12 @@ metadata::add_time_iso8601(pmt::pmt_t &m)
m = pmt::dict_add(m, pmt::mp(value(TIME)), pmt::mp(time_iso8601()));
}
void
metadata::add_pdu(pmt::pmt_t &m, const uint8_t *in, size_t len)
{
m = pmt::dict_add(m, pmt::mp(value(PDU)), pmt::make_blob(in, len));
}
/**
* Adds the CRC validity value
* @param m reference to a PMT dictionary
@ -137,12 +164,12 @@ metadata::to_json(const pmt::pmt_t& m)
v = pmt::dict_ref (m, pmt::mp (value (SYMBOL_ERASURES)), pmt::PMT_NIL);
if (!pmt::equal (v, pmt::PMT_NIL)) {
root[value (SAMPLE_START)] = Json::Value::UInt64(pmt::to_uint64 (v));
root[value (SYMBOL_ERASURES)] = Json::Value::UInt64(pmt::to_uint64 (v));
}
v = pmt::dict_ref (m, pmt::mp (value (CORRECTED_BITS)), pmt::PMT_NIL);
if (!pmt::equal (v, pmt::PMT_NIL)) {
root[value (SAMPLE_START)] = Json::Value::UInt64(pmt::to_uint64 (v));
root[value (CORRECTED_BITS)] = Json::Value::UInt64(pmt::to_uint64 (v));
}
return root;
}

View File

@ -48,6 +48,7 @@
#include "satnogs/lrpt_decoder.h"
#include "satnogs/lrpt_sync.h"
#include "satnogs/frame_acquisition.h"
#include "satnogs/metadata.h"
%}
@ -55,6 +56,7 @@
%include "satnogs/decoder.h"
%include "satnogs/amsat_duv_decoder.h"
%include "satnogs/ax25_decoder.h"
%include "satnogs/metadata.h"
%include "satnogs/morse_decoder.h"
GR_SWIG_BLOCK_MAGIC2(satnogs, morse_decoder);