From 361479d00f09c8fbe1ac7835b160dd1e560e18f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Est=C3=A9vez?= Date: Fri, 20 Dec 2019 15:34:11 +0000 Subject: [PATCH] Added standalone AAUSAT-4 decoder This removes the dependence on gr-aausat --- CHANGELOG.md | 1 + README.md | 2 - apps/aausat_4.grc | 285 ++++++++++++++---- grc/CMakeLists.txt | 2 + grc/satellites_aausat4_remove_fsm.block.yml | 21 ++ ...ellites_aausat4_telemetry_parser.block.yml | 13 + python/CMakeLists.txt | 3 + python/__init__.py | 3 + python/aausat4_remove_fsm.py | 51 ++++ python/aausat4_telemetry.py | 84 ++++++ python/aausat4_telemetry_parser.py | 53 ++++ 11 files changed, 463 insertions(+), 55 deletions(-) create mode 100644 grc/satellites_aausat4_remove_fsm.block.yml create mode 100644 grc/satellites_aausat4_telemetry_parser.block.yml create mode 100644 python/aausat4_remove_fsm.py create mode 100644 python/aausat4_telemetry.py create mode 100644 python/aausat4_telemetry_parser.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 0612f318..689443d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for SMOG-P and ATL-1 - Support for DUCHIFAT-3 - Support for OPS-SAT +- Standanlone decoder for AAUSAT-4 ### Changed - Replaced AO-40 synchronizer by more general distributed synchronizer - Replaced AO-40 deinterleaver by more general matrix deinterleaver diff --git a/README.md b/README.md index 2087bba0..41f6afa1 100644 --- a/README.md +++ b/README.md @@ -102,8 +102,6 @@ Required dependencies: The following GNUradio out-of-tree modules are only required for the decoder of one particular satellite. You may install only the ones you're interested in. - * [gr-aausat](https://github.com/daniestevez/gr-aausat) AAUSAT-4 decoder and - telemetry parser * [beesat-sdr](https://github.com/daniestevez/beesat-sdr) BEESAT and TECHNOSAT decoder and TNC. It is also used for D-STAR One. * [gr-lilacsat](https://github.com/bg2bhc/gr-lilacsat) This only needs to be installed if you want to submit telemetry to HIT. A complete decoder which does not use gr-lilacsat diff --git a/apps/aausat_4.grc b/apps/aausat_4.grc index 8c0865fc..a13537bb 100644 --- a/apps/aausat_4.grc +++ b/apps/aausat_4.grc @@ -56,35 +56,52 @@ blocks: coordinate: [1168, 92] rotation: 0 state: enabled -- name: aausat_aausat4_beacon_parser_0 - id: aausat_aausat4_beacon_parser +- name: viterbi_long + id: variable_cc_decoder_def parameters: - affinity: '' - alias: '' comment: '' + dim1: '1' + dim2: '1' + framebits: '1996' + k: '7' + mode: fec.CC_TERMINATED + ndim: '0' + padding: 'False' + polys: '[79,-109]' + rate: '2' + state_end: '-1' + state_start: '0' + value: '"ok"' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [592, 880] + coordinate: [944, 306] rotation: 0 - state: enabled -- name: aausat_aausat4_fec_0 - id: aausat_aausat4_fec + state: true +- name: viterbi_short + id: variable_cc_decoder_def parameters: - affinity: '' - alias: '' comment: '' - maxoutbuf: '0' - minoutbuf: '0' - verbose: 'False' + dim1: '1' + dim2: '1' + framebits: '1020' + k: '7' + mode: fec.CC_TERMINATED + ndim: '0' + padding: 'False' + polys: '[79,-109]' + rate: '2' + state_end: '-1' + state_start: '0' + value: '"ok"' states: bus_sink: false bus_source: false bus_structure: null - coordinate: [80, 916] + coordinate: [941, 111] rotation: 0 - state: enabled + state: true - name: blocks_multiply_const_vxx_0 id: blocks_multiply_const_vxx parameters: @@ -103,6 +120,42 @@ blocks: coordinate: [432, 260] rotation: 0 state: enabled +- name: blocks_packed_to_unpacked_xx_0 + id: blocks_packed_to_unpacked_xx + parameters: + affinity: '' + alias: '' + bits_per_chunk: '1' + comment: '' + endianness: gr.GR_MSB_FIRST + maxoutbuf: '0' + minoutbuf: '0' + num_ports: '1' + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [302, 795] + rotation: 0 + state: true +- name: blocks_pdu_to_tagged_stream_0 + id: blocks_pdu_to_tagged_stream + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + tag: packet_len + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [66, 803] + rotation: 0 + state: true - name: blocks_short_to_float_0 id: blocks_short_to_float parameters: @@ -120,6 +173,42 @@ blocks: coordinate: [248, 260] rotation: 0 state: enabled +- name: blocks_tagged_stream_multiply_length_0_0_0_0 + id: blocks_tagged_stream_multiply_length + parameters: + affinity: '' + alias: '' + c: '8' + comment: '' + lengthtagname: packet_len + maxoutbuf: '0' + minoutbuf: '0' + type: byte + vlen: '1' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [553, 803] + rotation: 0 + state: enabled +- name: blocks_tagged_stream_to_pdu_0 + id: blocks_tagged_stream_to_pdu + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + tag: packet_len + type: byte + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [712, 743] + rotation: 0 + state: true - name: blocks_udp_source_0 id: blocks_udp_source parameters: @@ -158,23 +247,8 @@ blocks: coordinate: [512, 15] rotation: 0 state: enabled -- name: digital_binary_slicer_fb_0 - id: digital_binary_slicer_fb - parameters: - affinity: '' - alias: '' - comment: '' - maxoutbuf: '0' - minoutbuf: '0' - states: - bus_sink: false - bus_source: false - bus_structure: null - coordinate: [376, 416] - rotation: 0 - state: enabled -- name: digital_binary_slicer_fb_0_0 - id: digital_binary_slicer_fb +- name: ccsds_descrambler_0 + id: ccsds_descrambler parameters: affinity: '' alias: '' @@ -185,7 +259,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [376, 680] + coordinate: [677, 664] rotation: 0 state: enabled - name: digital_clock_recovery_mm_xx_0 @@ -230,6 +304,44 @@ blocks: coordinate: [160, 648] rotation: 0 state: enabled +- name: fec_async_decoder_0 + id: fec_async_decoder + parameters: + affinity: '' + alias: '' + comment: '' + decoder: viterbi_long + maxoutbuf: '0' + minoutbuf: '0' + mtu: int(1996/8) + packed: 'False' + rev_pack: 'False' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [857, 578] + rotation: 0 + state: enabled +- name: fec_async_decoder_0_0 + id: fec_async_decoder + parameters: + affinity: '' + alias: '' + comment: '' + decoder: viterbi_short + maxoutbuf: '0' + minoutbuf: '0' + mtu: int(1020/8) + packed: 'True' + rev_pack: 'False' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [859, 513] + rotation: 0 + state: enabled - name: invert id: parameter parameters: @@ -324,6 +436,19 @@ blocks: coordinate: [16, 684] rotation: 0 state: enabled +- name: note_1 + id: note + parameters: + alias: '' + comment: '' + note: 'Workaround: this segfauls in unpacked mode' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [1038, 517] + rotation: 0 + state: true - name: port id: parameter parameters: @@ -358,6 +483,51 @@ blocks: coordinate: [720, 15] rotation: 0 state: enabled +- name: satellites_aausat4_check_fsm_0 + id: satellites_aausat4_check_fsm + parameters: + affinity: '' + alias: '' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [594, 541] + rotation: 0 + state: true +- name: satellites_aausat4_telemetry_parser_0 + id: satellites_aausat4_telemetry_parser + parameters: + affinity: '' + alias: '' + comment: '' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [989, 835] + rotation: 0 + state: true +- name: satellites_decode_rs_0 + id: satellites_decode_rs + parameters: + affinity: '' + alias: '' + basis: '0' + comment: '' + maxoutbuf: '0' + minoutbuf: '0' + verbose: 'True' + states: + bus_sink: false + bus_source: false + bus_structure: null + coordinate: [884, 652] + rotation: 0 + state: enabled - name: satellites_print_header_0 id: satellites_print_header parameters: @@ -368,7 +538,7 @@ blocks: bus_sink: false bus_source: false bus_structure: null - coordinate: [304, 960] + coordinate: [1001, 1032] rotation: 0 state: disabled - name: satellites_print_timestamp_0 @@ -407,58 +577,67 @@ blocks: coordinate: [968, 897] rotation: 0 state: enabled -- name: sync_to_pdu_packed_0 - id: sync_to_pdu_packed +- name: sync_to_pdu_soft_0 + id: sync_to_pdu_soft parameters: affinity: '' alias: '' comment: '' maxoutbuf: '0' minoutbuf: '0' - packlen: '251' + packlen: 1996+8 sync: access_code threshold: threshold states: bus_sink: false bus_source: false bus_structure: null - coordinate: [608, 396] + coordinate: [410, 400] rotation: 0 - state: enabled -- name: sync_to_pdu_packed_0_0 - id: sync_to_pdu_packed + state: true +- name: sync_to_pdu_soft_0_0 + id: sync_to_pdu_soft parameters: affinity: '' alias: '' comment: '' maxoutbuf: '0' minoutbuf: '0' - packlen: '251' + packlen: 1996+8 sync: access_code threshold: threshold states: bus_sink: false bus_source: false bus_structure: null - coordinate: [608, 660] + coordinate: [407, 664] rotation: 0 state: enabled connections: -- [aausat_aausat4_fec_0, out, satellites_print_header_0, in] -- [aausat_aausat4_fec_0, out, satellites_print_timestamp_0, in] -- [aausat_aausat4_fec_0, out, satellites_submit_0, in] - [blocks_multiply_const_vxx_0, '0', digital_clock_recovery_mm_xx_0, '0'] - [blocks_multiply_const_vxx_0, '0', digital_clock_recovery_mm_xx_0_0, '0'] +- [blocks_packed_to_unpacked_xx_0, '0', blocks_tagged_stream_multiply_length_0_0_0_0, + '0'] +- [blocks_pdu_to_tagged_stream_0, '0', blocks_packed_to_unpacked_xx_0, '0'] - [blocks_short_to_float_0, '0', blocks_multiply_const_vxx_0, '0'] +- [blocks_tagged_stream_multiply_length_0_0_0_0, '0', blocks_tagged_stream_to_pdu_0, + '0'] +- [blocks_tagged_stream_to_pdu_0, pdus, ccsds_descrambler_0, in] - [blocks_udp_source_0, '0', blocks_short_to_float_0, '0'] -- [digital_binary_slicer_fb_0, '0', sync_to_pdu_packed_0, '0'] -- [digital_binary_slicer_fb_0_0, '0', sync_to_pdu_packed_0_0, '0'] -- [digital_clock_recovery_mm_xx_0, '0', digital_binary_slicer_fb_0, '0'] -- [digital_clock_recovery_mm_xx_0_0, '0', digital_binary_slicer_fb_0_0, '0'] -- [satellites_print_timestamp_0, out, aausat_aausat4_beacon_parser_0, in] -- [sync_to_pdu_packed_0, out, aausat_aausat4_fec_0, in] -- [sync_to_pdu_packed_0_0, out, aausat_aausat4_fec_0, in] +- [ccsds_descrambler_0, out, satellites_decode_rs_0, in] +- [digital_clock_recovery_mm_xx_0, '0', sync_to_pdu_soft_0, '0'] +- [digital_clock_recovery_mm_xx_0_0, '0', sync_to_pdu_soft_0_0, '0'] +- [fec_async_decoder_0, out, ccsds_descrambler_0, in] +- [fec_async_decoder_0_0, out, blocks_pdu_to_tagged_stream_0, pdus] +- [satellites_aausat4_check_fsm_0, long, fec_async_decoder_0, in] +- [satellites_aausat4_check_fsm_0, short, fec_async_decoder_0_0, in] +- [satellites_decode_rs_0, out, satellites_print_timestamp_0, in] +- [satellites_print_timestamp_0, out, satellites_aausat4_telemetry_parser_0, in] +- [satellites_print_timestamp_0, out, satellites_print_header_0, in] +- [satellites_print_timestamp_0, out, satellites_submit_0, in] +- [sync_to_pdu_soft_0, out, satellites_aausat4_check_fsm_0, in] +- [sync_to_pdu_soft_0_0, out, satellites_aausat4_check_fsm_0, in] metadata: file_format: 1 diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 98977355..27b380ad 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -104,6 +104,8 @@ install(FILES satellites_smogp_packet_filter.block.yml satellites_smogp_telemetry_parser.block.yml satellites_smogp_spectrum_save.block.yml + satellites_aausat4_remove_fsm.block.yml + satellites_aausat4_telemetry_parser.block.yml CCSDS/satellites_space_packet_parser.block.yml CCSDS/satellites_telemetry_parser.block.yml CCSDS/satellites_telecommand_parser.block.yml diff --git a/grc/satellites_aausat4_remove_fsm.block.yml b/grc/satellites_aausat4_remove_fsm.block.yml new file mode 100644 index 00000000..d10b16b0 --- /dev/null +++ b/grc/satellites_aausat4_remove_fsm.block.yml @@ -0,0 +1,21 @@ +id: satellites_aausat4_check_fsm +label: AAUSAT-4 remove FSM +category: '[Satellites]/Coding' + +inputs: +- domain: message + id: in + +outputs: +- domain: message + id: short + optional: true +- domain: message + id: long + optional: true + +templates: + imports: import satellites + make: satellites.aausat4_remove_fsm() + +file_format: 1 diff --git a/grc/satellites_aausat4_telemetry_parser.block.yml b/grc/satellites_aausat4_telemetry_parser.block.yml new file mode 100644 index 00000000..53653193 --- /dev/null +++ b/grc/satellites_aausat4_telemetry_parser.block.yml @@ -0,0 +1,13 @@ +id: satellites_aausat4_telemetry_parser +label: AAUSAT4 Telemetry Parser +category: '[Satellites]/Telemetry' + +inputs: +- domain: message + id: in + +templates: + imports: import satellites + make: satellites.aausat4_telemetry_parser() + +file_format: 1 diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 0504f137..d7bbb266 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -124,6 +124,9 @@ GR_PYTHON_INSTALL( smogp_telemetry.py smogp_telemetry_parser.py smogp_spectrum_save.py + aausat4_remove_fsm.py + aausat4_telemetry.py + aausat4_telemetry_parser.py CCSDS/space_packet_parser.py CCSDS/space_packet.py CCSDS/telemetry.py diff --git a/python/__init__.py b/python/__init__.py index a0d8e788..6019bb35 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -150,3 +150,6 @@ from .smogp_packet_filter import smogp_packet_filter from .smogp_telemetry_parser import smogp_telemetry_parser from .smogp_spectrum_save import smogp_spectrum_save + +from .aausat4_remove_fsm import aausat4_remove_fsm +from .aausat4_telemetry_parser import aausat4_telemetry_parser diff --git a/python/aausat4_remove_fsm.py b/python/aausat4_remove_fsm.py new file mode 100644 index 00000000..baf14317 --- /dev/null +++ b/python/aausat4_remove_fsm.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2018-2019 Daniel Estevez . +# +# This 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, or (at your option) +# any later version. +# +# This software 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 software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +import numpy +from gnuradio import gr +import pmt +import array + +class aausat4_remove_fsm(gr.basic_block): + """ + docstring for block aausat4_remove_fsm + """ + def __init__(self): + gr.basic_block.__init__(self, + name="aausat4_remove_fsm", + in_sig=[], + out_sig=[]) + + self.message_port_register_in(pmt.intern('in')) + self.set_msg_handler(pmt.intern('in'), self.handle_msg) + self.message_port_register_out(pmt.intern('short')) + self.message_port_register_out(pmt.intern('long')) + + def handle_msg(self, msg_pmt): + msg = pmt.cdr(msg_pmt) + if not pmt.is_f32vector(msg): + print("[ERROR] Received invalid message type. Expected f32vector") + return + packet_short = pmt.f32vector_elements(msg)[8:8+1020] + packet_long = pmt.f32vector_elements(msg)[8:8+1996] + self.message_port_pub(pmt.intern('short'), + pmt.cons(pmt.PMT_NIL, pmt.init_f32vector(len(packet_short), packet_short))) + self.message_port_pub(pmt.intern('long'), + pmt.cons(pmt.PMT_NIL, pmt.init_f32vector(len(packet_long), packet_long))) diff --git a/python/aausat4_telemetry.py b/python/aausat4_telemetry.py new file mode 100644 index 00000000..3dd47ef5 --- /dev/null +++ b/python/aausat4_telemetry.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2019 Daniel Estevez +# +# This 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, or (at your option) +# any later version. +# +# This software 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 software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from construct import * +from .adapters import LinearAdapter + +EPS = Struct( + 'boot_count' / Int16ub, + 'uptime' / Int32ub, + 'rt_clock' / Int32ub, + 'ping_status' / Int8ub, + 'subsystem_status' / Int16ub, + 'battery_voltage' / LinearAdapter(1/40.0, Int8ub), + 'cell_diff' / LinearAdapter(1/4.0, Int8sb), + 'battery_current' / LinearAdapter(1/10.0, Int8sb), + 'solar_power' / LinearAdapter(1/20.0, Int8ub), + 'temp' / Int8sb, + 'pa_temp' / Int8sb, + 'main_voltage' / Int8sb + ) + +COM = Struct( + 'boot_count' / Int16ub, + 'packets_received' / Int16ub, + 'packets_sent' / Int16ub, + 'latest_rssi' / Int16sb, + 'latest_bit_correction' / Int8ub, + 'latest_byte_correction' / Int8ub + ) + +# Reverse-engineered + +ADCS1 = Struct( + 'bdot' / Int16sb[3], + 'state' / Int8ub + ) + +ADCS2 = Struct( + 'gyro' / Int16sb[3] + ) + +AIS = Struct( + 'boot_count' / Int16ub, + Padding(4), # unknown data + 'unique_mssi' / Int16ub, + Padding(12) # unknown data + ) + +Valid = BitStruct( + Padding(2), + 'ais2' / Flag, + 'ais1' / Flag, + 'adcs2' / Flag, + 'adcs1' / Flag, + 'com' / Flag, + 'eps' / Flag + ) +Beacon = Struct( + 'valid' / Valid, + 'eps' / EPS, + 'com' / COM, + 'adcs1' / ADCS1, + 'adcs2' / ADCS2, + 'ais1' / AIS, + 'ais2' / AIS + ) diff --git a/python/aausat4_telemetry_parser.py b/python/aausat4_telemetry_parser.py new file mode 100644 index 00000000..7df46cce --- /dev/null +++ b/python/aausat4_telemetry_parser.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2019 Daniel Estevez +# +# This 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, or (at your option) +# any later version. +# +# This software 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 software; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import numpy +from gnuradio import gr +import pmt + +from . import aausat4_telemetry + +class aausat4_telemetry_parser(gr.basic_block): + """ + docstring for block aausat4_telemetry_parser + """ + def __init__(self): + gr.basic_block.__init__(self, + name="aausat4_telemetry_parser", + in_sig=[], + out_sig=[]) + + self.message_port_register_in(pmt.intern('in')) + self.set_msg_handler(pmt.intern('in'), self.handle_msg) + + def handle_msg(self, msg_pmt): + msg = pmt.cdr(msg_pmt) + if not pmt.is_u8vector(msg): + print("[ERROR] Received invalid message type. Expected u8vector") + return + packet = bytes(pmt.u8vector_elements(msg)) + + try: + data = aausat4_telemetry.Beacon.parse(packet[6:]) # 2 bytes length + 4 bytes CSP header + except: + print("Could not decode telemetry beacon") + return + print(data)