File: dsat.py

package info (click to toggle)
gr-satellites 5.8.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,836 kB
  • sloc: python: 29,546; cpp: 5,448; ansic: 1,247; sh: 118; makefile: 24
file content (92 lines) | stat: -rw-r--r-- 2,944 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Copyright 2020 Daniel Estevez <daniel@destevez.net>
#
# This file is part of gr-satellites
#
# SPDX-License-Identifier: GPL-3.0-or-later
#

import struct
import datetime
import types

from .imagereceiver import ImageReceiver
from ..telemetry.csp import CSPHeader


class ImageReceiverDSAT(ImageReceiver):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._dsat_reset_segments()

    def _dsat_reset_segments(self):
        self._dsat_old_offset = 0
        self._dsat_current_segment = 0
        self._dsat_current_segment_size = None

    def _dsat_segment_size(self, chunk):
        return struct.unpack('>I', chunk[-4:])[0]

    def chunk_offset(self, chunk):
        offset = struct.unpack('>I', chunk[-8:-4])[0]
        # handle offset rollover
        if self._dsat_old_offset > offset:
            self.log('D-SAT offset rollover')
            if self._dsat_current_segment_size is None:
                self.log('unknown last segment size, '
                         'taking from current chunk')
                self._dsat_current_segment_size = (
                    self._dsat_segment_size(chunk))
            self._dsat_current_segment += self._dsat_current_segment_size
            self.log(f'current segment now {self._dsat_current_segment}')
        self._dsat_old_offset = offset
        self._dsat_current_segment_size = self._dsat_segment_size(chunk)
        return self._dsat_current_segment + offset

    def chunk_data(self, chunk):
        return chunk[4:-8]

    def filename(self, fid):
        return f'{fid}.jpg'

    def parse_chunk(self, chunk):
        if len(chunk) <= 15+8:
            return None
        header = CSPHeader.parse(chunk)
        # destination port 30 is used for JPEG blocks
        if header.destination_port != 30:
            return None
        return chunk

    def _watch_file_announcements(self, chunk):
        if len(chunk) < 25:
            return
        header = CSPHeader.parse(chunk)
        # destination port 12 is used for announcements
        if header.destination_port != 12:
            return

        timestamp = datetime.datetime.utcfromtimestamp(
            struct.unpack('<i', chunk[4:8])[0])
        fid = struct.unpack('<I', chunk[8:12])[0]
        # next 12 bytes are for GPS position
        length = struct.unpack('<I', chunk[21:25])[0]

        self.log(f'image {fid} announced. Length {length}. '
                 f'Timestamp {timestamp}')

        # hook lambda functions for file id and size
        self.file_id = types.MethodType(lambda self, chunk: fid, self)
        self.file_size = types.MethodType(lambda self, chunk: length, self)

        self._dsat_reset_segments()

    def push_chunk(self, chunk):
        # hook the file announcement watch here
        self._watch_file_announcements(chunk)
        super().push_chunk(chunk)


dsat = ImageReceiverDSAT