-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdecoder.py
More file actions
170 lines (132 loc) · 5.25 KB
/
decoder.py
File metadata and controls
170 lines (132 loc) · 5.25 KB
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
'''
CubeSail Beacon Decoder
Written with love by Jeremy DeJournett
2018/12/16
'''
from __future__ import print_function # nop in py3, adding py2 support
import struct
from struct import calcsize
import binascii
import sys
from collections import OrderedDict
# Little endian CPU
ENDIANNESS = "<"
def python3():
return sys.version_info[0] == 3
def get_string(description):
if python3():
return input(description)
else:
return raw_input(description)
def get_payload3():
print("Thank you SO MUCH for decoding a beacon for us, it means the world! Here's what you need to know:\n\n")
print("==> Communications settings:")
print("\tFrequency: 437.305MHz")
print("\tModulation: GMSK (GR3UH scrambling)")
print("\tBandwidth: 15kHz")
print("\tBaud rate: 9600")
print("\tLink Layer: AX.25/HDLC")
print("\tCallsign: WI2XVF")
print("\tTLE:\n")
print("cubesail_temp")
print("1 99999U 18350.31100694 .00048519 00000-0 21968-2 0 00004")
print("2 99999 085.0351 178.2861 0013006 291.7248 120.7146 15.20874873000012")
print("\n")
callsign = get_string('What is the callsign you received? (default: CQ) ')
if callsign == "":
callsign = "CQ "
print("\n\tNOTE: Payloads will come over RF in raw binary, but you may "
+"enter it just using the hexadecimal strings you're familiar with\n")
payload = get_string('What is the payload you received, in hexadecimal encoded ASCII? ')
return callsign, binascii.unhexlify(payload.replace('\r','').replace(' ','').replace('\n',''))
def scan_core(buf, offset, fmt):
try:
return struct.unpack_from(fmt, buf, offset)[0], offset+calcsize(fmt)
except struct.error:
pass
finally:
raise RuntimeError("\n\n[ERROR] The payload you provided is not long enough!\n\n")
def scan_double(buf, offset, endian=ENDIANNESS):
return scan_core(buf, offset, endian + "d")
def scan_u8(buf, offset, endian=ENDIANNESS):
return scan_core(buf, offset, endian + "B")
def scan_u16(buf, offset, endian=ENDIANNESS):
return scan_core(buf, offset, endian + "H")
def scan_float(buf, offset, endian=ENDIANNESS):
return scan_core(buf, offset, endian + "f")
def scan_u32(buf, offset, endian=ENDIANNESS):
return scan_core(buf, offset, endian + "L")
def scan_u64(buf, offset, endian=ENDIANNESS):
return scan_core(buf, offset, endian + "Q")
def scan_print3(description, value):
print('{:40s}\t:\t{}'.format(description, value))
def payload_dict(payload, endian=ENDIANNESS):
payload_d = OrderedDict()
offset = 0
section = 'Powerboard data'
for name in ['Pack A Total Voltage'
, 'Pack A Lower-Cell Voltage'
, 'Pack B Total Voltage'
, 'Pack B Lower-Cell Voltage'
, 'Pack A Upper-Cell Temperature'
, 'Pack A Lower-Cell Temperature'
, 'Pack B Upper-Cell Temperature'
, 'Pack B Lower-Cell Temperature']:
value, offset = scan_double(payload, offset, endian=endian)
payload_d[section, name] = value
section = 'ADCS data'
for name in ['q[0]'
, 'q[1]'
, 'q[2]'
, 'q[3]'
, 'w[0]'
, 'w[1]'
, 'w[2]']:
value, offset = scan_double(payload, offset, endian=endian)
payload_d[section, name] = value
value, offset = scan_u16(payload, offset, endian=endian)
payload_d[section, 'Illumination state'] = value
value, offset = scan_u8(payload, offset, endian=endian)
payload_d[section, 'Algorithm'] = value
section = 'Lithium Radio data (ignore)'
value, offset = scan_float(payload, offset, endian=endian)
payload_d[section, 'Radio Temperature'] = value
section = 'Health monitor data'
# HMD Beacon Data
value, offset = scan_u16(payload, offset, endian=endian)
payload_d[section, 'Sync bytes'] = value
value, offset = scan_u8(payload, offset, endian=endian)
payload_d[section, 'Host ID'] = value
value, offset = scan_u32(payload, offset, endian=endian)
payload_d[section, 'System time'] = value
value, offset = scan_u64(payload, offset, endian=endian)
payload_d[section, 'Recovery mode'] = value
value, offset = scan_float(payload, offset, endian=endian)
payload_d[section, 'C&DH Temperature'] = value
return payload_d
def print_payload_dict(payload_d):
prev_section = None
section_prefix = "\n==> "
for key, value in payload_d.items():
section, name = key
if prev_section is None:
print(section_prefix + section)
else:
if prev_section != section:
print(section_prefix + section)
scan_print3('\t'+name, value)
prev_section = section
def interactive_decode():
callsign, payload = get_payload3()
scan_print3("Callsign", callsign)
scan_print3("Payload", payload)
for endian, description in zip(
["<", ">"], ['Little endian', 'Big endian']):
print('\n\n<<===[[[ {} beacon data decoding ]]]===>>'.format(description))
payload_d = payload_dict(payload, endian=endian)
print_payload_dict(payload_d)
print('\n\nThank you for your help! Please email this printout to dejourn2@illinois.edu, with subject \"BEACON DATA\"')
def main():
interactive_decode()
if __name__ == '__main__':
main()