Implement a decoder covering COMMS from GOMSpace

This commit is contained in:
Manolis Surligas 2019-09-16 15:15:51 +03:00
parent c40b83211f
commit ab45da4ad3
21 changed files with 734 additions and 7 deletions

3
.gitignore vendored
View File

@ -8,4 +8,5 @@ apps/*.py
.cproject
.pyproject
.pydevproject
nbproject/
nbproject/
.vscode

View File

@ -50,7 +50,9 @@ list(APPEND enabled_blocks
satnogs_ogg_source.xml
satnogs_noaa_apt_sink.xml
satnogs_whitening.xml
satnogs_whitening_ccsds.xml
satnogs_ieee802_15_4_variant_decoder.xml
satnogs_ax100_decoder.xml
)
if(${INCLUDE_DEBUG_BLOCKS})

View File

@ -0,0 +1,74 @@
<?xml version="1.0"?>
<block>
<name>AX.100 Decoder Definition</name>
<key>variable_ax100_decoder</key>
<import>import satnogs</import>
<var_make>self.$(id) = $(id) = satnogs.ax100_decoder_make($preamble, $preamble_thrsh, $sync_word, $sync_thrsh, $crc, $whitening, $rs)</var_make>
<var_value>satnogs.ax100_decoder_make($preamble, $preamble_thrsh, $sync_word, $sync_thrsh, $crc, $whitening, $rs)</var_value>
<make></make>
<param>
<name>Ignore Me</name>
<key>value</key>
<value>'ok'</value>
<type>raw</type>
<hide>all</hide>
</param>
<param>
<name>Frame Preamble</name>
<key>preamble</key>
<value>[0x55, 0x55, 0x55, 0x55, 0x55]</value>
<type>raw</type>
</param>
<param>
<name>Preamble Threshold</name>
<key>preamble_thrsh</key>
<value>5</value>
<type>int</type>
</param>
<param>
<name>Synchronization Word</name>
<key>sync_word</key>
<value>[0x31, 0xe5]</value>
<type>raw</type>
</param>
<param>
<name>Synchronization Word Threshold</name>
<key>sync_thrsh</key>
<value>3</value>
<type>int</type>
</param>
<param>
<name>CRC</name>
<key>crc</key>
<value>None</value>
<type>raw</type>
</param>
<param>
<name>Whitening</name>
<key>whitening</key>
<value>None</value>
<type>raw</type>
</param>
<param>
<name>Reed Solomon</name>
<key>rs</key>
<value>True</value>
<type>enum</type>
<option>
<name>Enable</name>
<key>True</key>
</option>
<option>
<name>Disable</name>
<key>False</key>
</option>
</param>
</block>

View File

@ -5,6 +5,7 @@
<block>variable_ax25_decoder</block>
<block>variable_amsat_duv_decoder</block>
<block>variable_ieee802_15_4_variant_decoder</block>
<block>variable_ax100_decoder</block>
</cat>
<cat>
<name>Satellites</name>
@ -40,5 +41,6 @@
<block>satnogs_ax25_encoder_mb</block>
<block>satnogs_waterfall_sink</block>
<block>variable_whitening</block>
<block>variable_whitening_ccsds</block>
<block>satnogs_frame_decoder</block>
</cat>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<block>
<name>CCSDS Whitening</name>
<key>variable_whitening_ccsds</key>
<import>import satnogs</import>
<var_make>self.$(id) = $(id) = satnogs.whitening.make_ccsds()</var_make>
<var_value>satnogs.whitening.make_ccsds()</var_value>
<make></make>
<param>
<name>Ignore Me</name>
<key>value</key>
<value>'ok'</value>
<type>raw</type>
<hide>all</hide>
</param>
</block>

View File

@ -28,6 +28,7 @@ list(APPEND DEBUG_HEADER_FILES
)
list(APPEND HEADER_FILES
ax100_decoder.h
amsat_duv_decoder.h
api.h
ax25.h

View File

@ -0,0 +1,117 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* 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/>.
*/
#ifndef INCLUDED_SATNOGS_AX100_DECODER_H
#define INCLUDED_SATNOGS_AX100_DECODER_H
#include <satnogs/api.h>
#include <satnogs/decoder.h>
#include <satnogs/shift_reg.h>
#include <satnogs/crc.h>
#include <satnogs/whitening.h>
namespace gr {
namespace satnogs {
/*!
* \brief This decoder tries to cover all the supported framing and coding
* schemes of the AX100 product from GOMSpace. It also supports some variants
* that have appear in different missions, including excet the ASM and a
* repeated preamble
*
*/
class SATNOGS_API ax100_decoder : public decoder {
public:
static decoder_sptr
make(const std::vector<uint8_t> &preamble,
size_t preamble_threshold,
const std::vector<uint8_t> &sync,
size_t sync_threshold,
crc::crc_t crc,
whitening::whitening_sptr descrambler,
bool enable_rs);
ax100_decoder(const std::vector<uint8_t> &preamble,
size_t preamble_threshold,
const std::vector<uint8_t> &sync,
size_t sync_threshold,
crc::crc_t crc,
whitening::whitening_sptr descrambler,
bool enable_rs);
~ax100_decoder();
decoder_status_t
decode(const void *in, int len);
void
reset();
size_t
input_multiple() const;
private:
/**
* Decoding FSM
*/
typedef enum {
SEARCHING, //!< when searching for the start of the preamble
SEARCHING_SYNC, //!< We have preamble, search for sync
DECODING_FRAME_LEN, //!< Decoding the frame length
DECODING_PAYLOAD //!< Decoding the payload
} decoding_state_t;
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;
crc::crc_t d_crc;
whitening::whitening_sptr d_descrambler;
const bool d_rs;
decoding_state_t d_state;
size_t d_cnt;
size_t d_len;
size_t d_length_field_len;
uint8_t *d_pdu;
int
search_preamble(const uint8_t *in, int len);
int
search_sync(const uint8_t *in, int len);
int
decode_frame_len(const uint8_t *in, int len);
void
decode_payload(decoder_status_t &status, const uint8_t *in, int len);
bool
check_crc();
};
} // namespace satnogs
} // namespace gr
#endif /* INCLUDED_SATNOGS_AX100_DECODER_H */

View File

@ -38,6 +38,7 @@ public:
CRC16_CCITT_REVERSED,
CRC16_AX25,
CRC16_IBM,
CRC32_C,
CRC_METHODS_NUM
} crc_t;
@ -53,12 +54,16 @@ public:
static uint16_t
crc16_ibm(const uint8_t *data, size_t len);
static uint32_t
crc32_c(const uint8_t *data, size_t len);
static size_t
crc_size(crc_t t);
private:
static const uint16_t crc16_ccitt_table_reverse[256];
static const uint16_t crc16_ccitt_table[256];
static const uint32_t crc32_c_table[256];
};
} // namespace satnogs

View File

@ -102,7 +102,7 @@ public:
private:
/**
* Decoding FSM
* Decoding FSM states
*/
typedef enum {
SEARCHING, //!< when searching for the start of the preamble

View File

@ -200,6 +200,15 @@ crc32(const uint8_t *buf, size_t len)
return crc;
}
static void
print_pdu(const uint8_t *buf, size_t len)
{
for (size_t i = 0; i < len; i++) {
printf("0x%02x ", buf[i]);
}
printf("\n");
}
} // namespace satnogs
} // namespace gr

View File

@ -44,6 +44,9 @@ public:
static whitening_sptr
make(uint32_t mask, uint32_t seed, uint32_t order);
static whitening_sptr
make_ccsds();
whitening(uint32_t mask, uint32_t seed, uint32_t order);
~whitening();

View File

@ -76,7 +76,8 @@ list(APPEND satnogs_sources
ax25_decoder.cc
json_converter_impl.cc
ieee802_15_4_variant_decoder.cc
crc.cc)
crc.cc
ax100_decoder.cc)
if(${INCLUDE_DEBUG_BLOCKS})
list(APPEND satnogs_sources ${satnogs_debug_sources})
@ -129,6 +130,7 @@ list(APPEND test_satnogs_sources
${CMAKE_CURRENT_SOURCE_DIR}/qa_golay24.cc
${CMAKE_CURRENT_SOURCE_DIR}/test_satnogs.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_satnogs.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_ax100_decoder.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_crc.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_ieee802_15_4_variant_decoder.cc
${CMAKE_CURRENT_SOURCE_DIR}/qa_json_converter.cc

325
lib/ax100_decoder.cc Normal file
View File

@ -0,0 +1,325 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* 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 <satnogs/ax100_decoder.h>
#include <satnogs/golay24.h>
#include <satnogs/metadata.h>
#include <satnogs/utils.h>
#include <satnogs/log.h>
extern "C" {
#include <fec.h>
}
namespace gr {
namespace satnogs {
decoder::decoder_sptr
ax100_decoder::make(const std::vector<uint8_t> &preamble,
size_t preamble_threshold,
const std::vector<uint8_t> &sync, size_t sync_threshold,
crc::crc_t crc, whitening::whitening_sptr descrambler,
bool enable_rs)
{
return decoder::decoder_sptr(
new ax100_decoder(preamble, preamble_threshold, sync, sync_threshold,
crc, descrambler, enable_rs));
}
ax100_decoder::ax100_decoder(const std::vector<uint8_t> &preamble,
size_t preamble_threshold,
const std::vector<uint8_t> &sync,
size_t sync_threshold,
crc::crc_t crc,
whitening::whitening_sptr descrambler,
bool enable_rs) :
decoder(sizeof(uint8_t), enable_rs ? 255 : 1024),
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_crc(crc),
d_descrambler(descrambler),
d_rs(enable_rs),
d_state(SEARCHING),
d_cnt(0),
d_len(0),
/* Coded Golay 24 bits */
d_length_field_len(3),
d_pdu(new uint8_t[1024])
{
for (uint8_t b : preamble) {
d_preamble <<= (b >> 7);
d_preamble <<= ((b >> 6) & 0x1);
d_preamble <<= ((b >> 5) & 0x1);
d_preamble <<= ((b >> 4) & 0x1);
d_preamble <<= ((b >> 3) & 0x1);
d_preamble <<= ((b >> 2) & 0x1);
d_preamble <<= ((b >> 1) & 0x1);
d_preamble <<= (b & 0x1);
}
for (uint8_t b : sync) {
d_sync <<= (b >> 7);
d_sync <<= ((b >> 6) & 0x1);
d_sync <<= ((b >> 5) & 0x1);
d_sync <<= ((b >> 4) & 0x1);
d_sync <<= ((b >> 3) & 0x1);
d_sync <<= ((b >> 2) & 0x1);
d_sync <<= ((b >> 1) & 0x1);
d_sync <<= (b & 0x1);
}
if (d_sync_len < 8) {
throw std::invalid_argument("SYNC word 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");
}
}
ax100_decoder::~ax100_decoder()
{
delete[] d_pdu;
}
decoder_status_t
ax100_decoder::decode(const void *in, int len)
{
decoder_status_t status;
switch (d_state) {
case SEARCHING:
status.consumed = search_preamble((const uint8_t *) in, len);
break;
case SEARCHING_SYNC:
status.consumed = search_sync((const uint8_t *) in, len);
break;
case DECODING_FRAME_LEN:
status.consumed = decode_frame_len((const uint8_t *) in, len);
break;
case DECODING_PAYLOAD:
decode_payload(status, (const uint8_t *) in, len);
break;
default:
throw std::runtime_error("ax100_decoder: Invalid decoding state");
}
return status;
}
void
ax100_decoder::reset()
{
if (d_descrambler) {
d_descrambler->reset();
}
d_cnt = 0;
d_state = SEARCHING;
d_preamble_shift_reg.reset();
d_sync_shift_reg.reset();
}
size_t
ax100_decoder::input_multiple() const
{
return 8;
}
int
ax100_decoder::search_preamble(const uint8_t *in, int len)
{
/* We support also cases, where a repeated preamble is not used (pure CCSDS )*/
if (d_preamble_len == 0) {
d_state = SEARCHING_SYNC;
return search_sync(in, 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
ax100_decoder::search_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) {
LOG_WARN("Decoding");
d_state = DECODING_FRAME_LEN;
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
ax100_decoder::decode_frame_len(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_length_field_len) {
uint32_t coded_len = (d_pdu[0] << 16) | (d_pdu[1] << 8) | d_pdu[2];
print_pdu((const uint8_t *)&coded_len, 4);
uint32_t len;
golay24 g = golay24();
if (g.decode24(&len, coded_len)) {
d_len = len & 0xFF;
//d_len += crc::crc_size(d_crc);
LOG_WARN("Len: %u", d_len);
if (d_len > max_frame_len()) {
reset();
return (i + 1) * 8;
}
/* All good! Proceed with decoding */
d_cnt = 0;
d_state = DECODING_PAYLOAD;
memset(d_pdu, 0, max_frame_len());
return (i + 1) * 8;
}
else {
reset();
return (i + 1) * 8;
}
}
}
return s * 8;
}
void
ax100_decoder::decode_payload(decoder_status_t &status,
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_len) {
if (d_descrambler) {
d_descrambler->descramble(d_pdu, d_pdu, d_len, false);
}
metadata::add_time_iso8601(status.data);
/* If RS is used tru to decode the received frame */
if (d_rs) {
int ret = decode_rs_8(d_pdu, NULL, 0, 255 - d_len);
/* Drop the parity */
d_len -= 32;
if (ret > - 1) {
metadata::add_corrected_bits(status.data, ret);
}
else {
reset();
status.consumed = (i + 1) * 8;
return;
}
}
metadata::add_time_iso8601(status.data);
metadata::add_pdu(status.data, d_pdu, d_len - crc::crc_size(d_crc));
metadata::add_crc_valid(status.data, check_crc());
reset();
status.decode_success = true;
status.consumed = (i + 1) * 8;
return;
}
}
status.consumed = s * 8;
}
bool
ax100_decoder::check_crc()
{
uint16_t crc16_c;
uint16_t crc16_received;
uint32_t crc32_c;
uint32_t crc32_received;
switch (d_crc) {
case crc::CRC_NONE:
return true;
case crc::CRC32_C:
crc32_c = crc::crc32_c(d_pdu, d_len - 4);
memcpy(&crc32_received, d_pdu + d_len - 4, 4);
crc32_received = ntohl(crc32_received);
LOG_WARN("Received: 0x%02x Computed: 0x%02x", crc32_received, crc32_c);
//print_pdu(d_pdu, d_len);
if (crc32_c == crc32_received) {
return true;
}
return false;
default:
throw std::runtime_error("ax100_decoder: Invalid CRC");
}
}
} /* namespace satnogs */
} /* namespace gr */

View File

@ -93,6 +93,57 @@ const uint16_t crc::crc16_ccitt_table[256] = {
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
/*
* Slicing-by-8 software
*
* The following CRC lookup table was generated automagically
* using the following model parameters:
*
* Generator Polynomial = ................. 0x1EDC6F41
* Generator Polynomial Length = .......... 32 bits
* Reflected Bits = ....................... TRUE
* Table Generation Offset = .............. 32 bits
* Number of Slices = ..................... 8 slices
* Slice Lengths = ........................ 8 8 8 8 8 8 8 8
* Directory Name = ....................... .\
* File Name = ............................ 8x256_tables.c
*/
const uint32_t crc::crc32_c_table[256] = {
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
};
uint16_t
crc::crc16_ccitt_reversed(const uint8_t *data, size_t len)
{
@ -165,11 +216,24 @@ crc::crc_size(crc_t t)
case CRC16_AX25:
case CRC16_IBM:
return sizeof(uint16_t);
case CRC32_C:
return sizeof(uint32_t);
default:
throw std::invalid_argument("crc: Invalid CRC method");
}
}
uint32_t
crc::crc32_c(const uint8_t *data, size_t len)
{
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < len; i++) {
crc = (crc >> 8) ^ crc::crc32_c_table[(crc ^ data[i]) & 0xff];
}
return crc ^ 0xFFFFFFFF;
}
} /* namespace satnogs */
} /* namespace gr */

View File

@ -326,6 +326,8 @@ ieee802_15_4_variant_decoder::check_crc()
{
uint16_t crc16_c;
uint16_t crc16_received;
uint32_t crc32_c;
uint32_t crc32_received;
switch (d_crc) {
case crc::CRC_NONE:
return true;
@ -351,11 +353,20 @@ ieee802_15_4_variant_decoder::check_crc()
crc16_c = crc::crc16_ibm(d_pdu, d_len + d_length_field_len - 2);
memcpy(&crc16_received, d_pdu + d_length_field_len + d_len - 2, 2);
crc16_received = ntohs(crc16_received);
LOG_WARN("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
LOG_DEBUG("Received: 0x%02x Computed: 0x%02x", crc16_received, crc16_c);
if (crc16_c == crc16_received) {
return true;
}
return false;
case crc::CRC32_C:
crc32_c = crc::crc32_c(d_pdu, d_len + d_length_field_len - 4);
memcpy(&crc32_received, d_pdu + d_length_field_len + d_len - 4, 4);
crc32_received = ntohl(crc32_received);
LOG_DEBUG("Received: 0x%02x Computed: 0x%02x", crc32_received, crc32_c);
if (crc32_c == crc32_received) {
return true;
}
return false;
default:
throw std::runtime_error("ieee802_15_4_variant_decoder: Invalid CRC");
}

37
lib/qa_ax100_decoder.cc Normal file
View File

@ -0,0 +1,37 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* 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/>.
*/
#include <gnuradio/attributes.h>
#include <cppunit/TestAssert.h>
#include "qa_ax100_decoder.h"
#include <satnogs/ax100_decoder.h>
namespace gr {
namespace satnogs {
void
qa_ax100_decoder::t1()
{
// Put test here
}
} /* namespace satnogs */
} /* namespace gr */

44
lib/qa_ax100_decoder.h Normal file
View File

@ -0,0 +1,44 @@
/* -*- c++ -*- */
/*
* gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module
*
* Copyright (C) 2019, Libre Space Foundation <http://libre.space>
*
* 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/>.
*/
#ifndef _QA_AX100_DECODER_H_
#define _QA_AX100_DECODER_H_
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestCase.h>
namespace gr {
namespace satnogs {
class qa_ax100_decoder : public CppUnit::TestCase {
public:
CPPUNIT_TEST_SUITE(qa_ax100_decoder);
CPPUNIT_TEST(t1);
CPPUNIT_TEST_SUITE_END();
private:
void t1();
};
} /* namespace satnogs */
} /* namespace gr */
#endif /* _QA_AX100_DECODER_H_ */

View File

@ -24,6 +24,7 @@
#include "qa_json_converter.h"
#include "qa_ieee802_15_4_variant_decoder.h"
#include "qa_crc.h"
#include "qa_ax100_decoder.h"
CppUnit::TestSuite *
qa_satnogs::suite()
@ -34,5 +35,6 @@ qa_satnogs::suite()
s->addTest(gr::satnogs::qa_json_converter::suite());
s->addTest(gr::satnogs::qa_ieee802_15_4_variant_decoder::suite());
s->addTest(gr::satnogs::qa_crc::suite());
s->addTest(gr::satnogs::qa_ax100_decoder::suite());
return s;
}

View File

@ -36,9 +36,6 @@ shift_reg::shift_reg(size_t len)
: d_len(len),
d_reg(len, 0)
{
if (len < 1) {
throw std::invalid_argument("Shift register should contain at least one stage");
}
}
shift_reg::~shift_reg()

View File

@ -46,6 +46,17 @@ whitening::make(uint32_t mask, uint32_t seed, uint32_t order)
}
/**
* CCSDS compliant data whitening
* @return shared pointer to a CCSDS compliant scrambler/descrambler
*/
whitening::whitening_sptr
whitening::make_ccsds()
{
return make(0xA9, 0xFF, 7);
}
/**
* Data whitening and de-whitening class
* @param mask the polynomial mask

View File

@ -15,6 +15,7 @@
%{
#include "satnogs/amsat_duv_decoder.h"
#include "satnogs/ax100_decoder.h"
#include "satnogs/ax25_decoder.h"
#include "satnogs/morse_tree.h"
#include "satnogs/morse_decoder.h"
@ -53,8 +54,11 @@
%include "satnogs/amsat_duv_decoder.h"
%include "satnogs/ax25_decoder.h"
%include "satnogs/metadata.h"
/* crc.h should come first. All classes using it should be included afterwards */
%include "satnogs/crc.h"
%include "satnogs/ieee802_15_4_variant_decoder.h"
%include "satnogs/ax100_decoder.h"
%include "satnogs/morse_decoder.h"
GR_SWIG_BLOCK_MAGIC2(satnogs, morse_decoder);