diff --git a/.gitignore b/.gitignore index 4e2c807..4977293 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ apps/*.py .cproject .pyproject .pydevproject -nbproject/ \ No newline at end of file +nbproject/ +.vscode diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 0c42bea..010e10f 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -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}) diff --git a/grc/satnogs_ax100_decoder.xml b/grc/satnogs_ax100_decoder.xml new file mode 100644 index 0000000..0ba042e --- /dev/null +++ b/grc/satnogs_ax100_decoder.xml @@ -0,0 +1,74 @@ + + + AX.100 Decoder Definition + variable_ax100_decoder + import satnogs + self.$(id) = $(id) = satnogs.ax100_decoder_make($preamble, $preamble_thrsh, $sync_word, $sync_thrsh, $crc, $whitening, $rs) + satnogs.ax100_decoder_make($preamble, $preamble_thrsh, $sync_word, $sync_thrsh, $crc, $whitening, $rs) + + + Ignore Me + value + 'ok' + raw + all + + + + Frame Preamble + preamble + [0x55, 0x55, 0x55, 0x55, 0x55] + raw + + + + Preamble Threshold + preamble_thrsh + 5 + int + + + + Synchronization Word + sync_word + [0x31, 0xe5] + raw + + + + Synchronization Word Threshold + sync_thrsh + 3 + int + + + + CRC + crc + None + raw + + + + Whitening + whitening + None + raw + + + + Reed Solomon + rs + True + enum + + + + + \ No newline at end of file diff --git a/grc/satnogs_block_tree.xml b/grc/satnogs_block_tree.xml index 19a4346..3d26ba9 100644 --- a/grc/satnogs_block_tree.xml +++ b/grc/satnogs_block_tree.xml @@ -5,6 +5,7 @@ variable_ax25_decoder variable_amsat_duv_decoder variable_ieee802_15_4_variant_decoder + variable_ax100_decoder Satellites @@ -40,5 +41,6 @@ satnogs_ax25_encoder_mb satnogs_waterfall_sink variable_whitening + variable_whitening_ccsds satnogs_frame_decoder \ No newline at end of file diff --git a/grc/satnogs_whitening_ccsds.xml b/grc/satnogs_whitening_ccsds.xml new file mode 100644 index 0000000..af64907 --- /dev/null +++ b/grc/satnogs_whitening_ccsds.xml @@ -0,0 +1,16 @@ + + + CCSDS Whitening + variable_whitening_ccsds + import satnogs + self.$(id) = $(id) = satnogs.whitening.make_ccsds() + satnogs.whitening.make_ccsds() + + + Ignore Me + value + 'ok' + raw + all + + diff --git a/include/satnogs/CMakeLists.txt b/include/satnogs/CMakeLists.txt index d8bc7d0..d846b80 100644 --- a/include/satnogs/CMakeLists.txt +++ b/include/satnogs/CMakeLists.txt @@ -28,6 +28,7 @@ list(APPEND DEBUG_HEADER_FILES ) list(APPEND HEADER_FILES + ax100_decoder.h amsat_duv_decoder.h api.h ax25.h diff --git a/include/satnogs/ax100_decoder.h b/include/satnogs/ax100_decoder.h new file mode 100644 index 0000000..c55db89 --- /dev/null +++ b/include/satnogs/ax100_decoder.h @@ -0,0 +1,117 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, Libre Space Foundation + * + * 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 . + */ + +#ifndef INCLUDED_SATNOGS_AX100_DECODER_H +#define INCLUDED_SATNOGS_AX100_DECODER_H + +#include +#include +#include +#include +#include + +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 &preamble, + size_t preamble_threshold, + const std::vector &sync, + size_t sync_threshold, + crc::crc_t crc, + whitening::whitening_sptr descrambler, + bool enable_rs); + + ax100_decoder(const std::vector &preamble, + size_t preamble_threshold, + const std::vector &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 */ + diff --git a/include/satnogs/crc.h b/include/satnogs/crc.h index 2f71cd0..0566185 100644 --- a/include/satnogs/crc.h +++ b/include/satnogs/crc.h @@ -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 diff --git a/include/satnogs/ieee802_15_4_variant_decoder.h b/include/satnogs/ieee802_15_4_variant_decoder.h index 99778b6..48b9aa0 100644 --- a/include/satnogs/ieee802_15_4_variant_decoder.h +++ b/include/satnogs/ieee802_15_4_variant_decoder.h @@ -102,7 +102,7 @@ public: private: /** - * Decoding FSM + * Decoding FSM states */ typedef enum { SEARCHING, //!< when searching for the start of the preamble diff --git a/include/satnogs/utils.h b/include/satnogs/utils.h index c143ee2..03f76cd 100644 --- a/include/satnogs/utils.h +++ b/include/satnogs/utils.h @@ -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 diff --git a/include/satnogs/whitening.h b/include/satnogs/whitening.h index 9657b27..0dbb6e1 100644 --- a/include/satnogs/whitening.h +++ b/include/satnogs/whitening.h @@ -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(); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9ff5782..8111a68 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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 diff --git a/lib/ax100_decoder.cc b/lib/ax100_decoder.cc new file mode 100644 index 0000000..44a6b00 --- /dev/null +++ b/lib/ax100_decoder.cc @@ -0,0 +1,325 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, Libre Space Foundation + * + * 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 . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +namespace gr { +namespace satnogs { + +decoder::decoder_sptr +ax100_decoder::make(const std::vector &preamble, + size_t preamble_threshold, + const std::vector &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 &preamble, + size_t preamble_threshold, + const std::vector &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 */ diff --git a/lib/crc.cc b/lib/crc.cc index f4eba94..2e1f942 100644 --- a/lib/crc.cc +++ b/lib/crc.cc @@ -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 */ + diff --git a/lib/ieee802_15_4_variant_decoder.cc b/lib/ieee802_15_4_variant_decoder.cc index c7fa7ee..4e0d014 100644 --- a/lib/ieee802_15_4_variant_decoder.cc +++ b/lib/ieee802_15_4_variant_decoder.cc @@ -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"); } diff --git a/lib/qa_ax100_decoder.cc b/lib/qa_ax100_decoder.cc new file mode 100644 index 0000000..357db39 --- /dev/null +++ b/lib/qa_ax100_decoder.cc @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, Libre Space Foundation + * + * 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 . + */ + +#include +#include +#include "qa_ax100_decoder.h" +#include + +namespace gr { +namespace satnogs { + +void +qa_ax100_decoder::t1() +{ + // Put test here +} + +} /* namespace satnogs */ +} /* namespace gr */ + diff --git a/lib/qa_ax100_decoder.h b/lib/qa_ax100_decoder.h new file mode 100644 index 0000000..1202c82 --- /dev/null +++ b/lib/qa_ax100_decoder.h @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, Libre Space Foundation + * + * 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 . + */ + +#ifndef _QA_AX100_DECODER_H_ +#define _QA_AX100_DECODER_H_ + +#include +#include + +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_ */ + diff --git a/lib/qa_satnogs.cc b/lib/qa_satnogs.cc index 392ea2d..8097c4f 100644 --- a/lib/qa_satnogs.cc +++ b/lib/qa_satnogs.cc @@ -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; } diff --git a/lib/shift_reg.cc b/lib/shift_reg.cc index 3c34889..84b4bd7 100644 --- a/lib/shift_reg.cc +++ b/lib/shift_reg.cc @@ -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() diff --git a/lib/whitening.cc b/lib/whitening.cc index 0685e1c..0ed72d3 100644 --- a/lib/whitening.cc +++ b/lib/whitening.cc @@ -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 diff --git a/swig/satnogs_swig0.i b/swig/satnogs_swig0.i index 5e861ba..fbd219e 100644 --- a/swig/satnogs_swig0.i +++ b/swig/satnogs_swig0.i @@ -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);