Use the shift register approach for the DUV decoder
This commit is contained in:
parent
c5f376929c
commit
c9f685d1c1
|
@ -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] =
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue