Skip to content

Commit ffd7dbe

Browse files
committed
add working ticking beacon
1 parent 6dfa4b4 commit ffd7dbe

5 files changed

+205
-188
lines changed

Diff for: CCSDS_Beacon_Decoder.py

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from CCSDS_Parsed_Beacon import CCSDS_Parsed_Beacon
2+
3+
4+
class CCSDS_Beacon_Decoder:
5+
def __init__(self):
6+
pass
7+
8+
def parse(self, packet):
9+
# header = packet[0:6]
10+
# telemetry_packet_type = packet[6]
11+
12+
ttnc_field = packet[7:9]
13+
ret_ttnc = self._parse_ttnc_field(ttnc_field)
14+
15+
adcs_field = packet[9:21]
16+
ret_adcs = self._parse_adcs_field(adcs_field)
17+
18+
eps_field = packet[21:27]
19+
ret_eps = self._parse_eps_field(eps_field)
20+
21+
payload_field = packet[27:31]
22+
ret_payload = self._parse_payload_field(payload_field)
23+
24+
timestamp_field = packet[31:]
25+
ret_timestamp = self._parse_timestamp_field(timestamp_field)
26+
27+
return CCSDS_Parsed_Beacon(ret_ttnc, ret_adcs, ret_eps, ret_payload, ret_timestamp)
28+
29+
def _parse_ttnc_field(self, ttnc_field):
30+
# Decode mode
31+
mode_lookup = {0: 'FU1', 1: 'FU2', 2: 'FU3', 3: 'FU4'}
32+
mode_bits = (ttnc_field[0] & 0b01100000) >> 5
33+
mode = mode_lookup.get(mode_bits)
34+
35+
# Decode baud
36+
baud_lookup = {0: '1200', 1: '2400', 2: '4800', 3: '9600',
37+
4: '19200', 5: '38400', 6: '57600', 7: '115200'}
38+
baud_bits = (ttnc_field[0] & 0b00011100) >> 2
39+
baud = baud_lookup.get(baud_bits)
40+
41+
# Channel
42+
channel_bits = ((ttnc_field[0] & 0b00000011)
43+
<< 5) | (ttnc_field[1] >> 3)
44+
channel = str(int(f'{channel_bits:#0}'))
45+
46+
# Transmit Power
47+
tx_power_lookup = {0: '-1', 1: '2', 2: '5',
48+
3: '8', 4: '11', 5: '14', 6: '17', 7: '20'}
49+
tx_power_bits = (ttnc_field[1] & 0b111)
50+
tx_power = tx_power_lookup.get(tx_power_bits)
51+
52+
ret_ttnc = {'Transmission Mode': mode, 'Baud Rate': baud,
53+
'Channel': channel, 'Transmit Power': tx_power}
54+
return ret_ttnc
55+
56+
def _parse_adcs_field(self, adcs_field):
57+
# Decode gx
58+
gx = int.from_bytes(adcs_field[0:2], byteorder='big', signed=True)
59+
60+
# Decode gy
61+
gy = int.from_bytes(adcs_field[2:4], byteorder='big', signed=True)
62+
63+
# Decode gz
64+
gz = int.from_bytes(adcs_field[4:6], byteorder='big', signed=True)
65+
66+
# Decode mx
67+
mx = int.from_bytes(adcs_field[6:8], byteorder='big', signed=True)
68+
69+
# Decode my
70+
my = int.from_bytes(adcs_field[8:10], byteorder='big', signed=True)
71+
72+
# Decode mz
73+
mz = int.from_bytes(
74+
adcs_field[10:12], byteorder='big', signed=True)
75+
76+
ret_adcs = {'gx': gx, 'gy': gy, 'gz': gz,
77+
'mx': mx, 'my': my, 'mz': mz}
78+
return ret_adcs
79+
80+
def _parse_eps_field(self, eps_field):
81+
temp_int = int.from_bytes(
82+
eps_field[0:3], byteorder='big', signed=True)
83+
temp = temp_int / 100
84+
reserved = int.from_bytes(
85+
eps_field[3:6], byteorder='big', signed=True)
86+
87+
return {'Temperature': temp, 'Reserved': reserved}
88+
89+
def _parse_payload_field(self, payload_field):
90+
r1 = payload_field[0]
91+
r2 = payload_field[1]
92+
r3 = payload_field[2]
93+
r4 = payload_field[3]
94+
95+
ret_payload = {'Reserved byte 1': r1, 'Reserved byte 2': r2,
96+
'Reserved byte 3': r3, 'Reserved byte 4': r4}
97+
return ret_payload
98+
99+
def _parse_timestamp_field(self, timestamp_field):
100+
DD = timestamp_field[0]
101+
MM = timestamp_field[1]
102+
YYYY = int.from_bytes(
103+
timestamp_field[2:4], byteorder='big', signed=False)
104+
hh = timestamp_field[4]
105+
mm = timestamp_field[5]
106+
ss = timestamp_field[6]
107+
108+
ret_timestamp = {"DD": DD, "MM": MM,
109+
"YYYY": YYYY, "hh": hh, "mm": mm, "ss": ss}
110+
return ret_timestamp

Diff for: CCSDS_Parsed_Beacon.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
class CCSDS_Parsed_Beacon:
2+
def __init__(self, ret_ttnc, ret_adcs, ret_eps, ret_payload, ret_timestamp):
3+
self.ret = {'TT&C': ret_ttnc, 'ADCS': ret_adcs, 'EPS': ret_eps,
4+
'Payload': ret_payload, 'Timestamp': ret_timestamp}
5+
6+
# Unpack ttnc
7+
self.mode = ret_ttnc['Transmission Mode']
8+
self.baud = ret_ttnc['Baud Rate']
9+
self.channel = ret_ttnc['Channel']
10+
self.tx_power = ret_ttnc['Transmit Power']
11+
12+
# Unpack adcs
13+
self.gx = ret_adcs['gx']
14+
self.gy = ret_adcs['gy']
15+
self.gz = ret_adcs['gz']
16+
self.mx = ret_adcs['mx']
17+
self.my = ret_adcs['my']
18+
self.mz = ret_adcs['mz']
19+
20+
# Unpack eps
21+
self.temp = ret_eps['Temperature']
22+
self.eps_reserved = ret_eps['Reserved']
23+
24+
# Unpack payload
25+
self.r1 = ret_payload['Reserved byte 1']
26+
self.r2 = ret_payload['Reserved byte 2']
27+
self.r3 = ret_payload['Reserved byte 3']
28+
self.r4 = ret_payload['Reserved byte 4']
29+
30+
# Unpack timestamp
31+
self.ts_DD = ret_timestamp['DD']
32+
self.ts_MM = ret_timestamp['MM']
33+
self.ts_YYYY = ret_timestamp['YYYY']
34+
self.ts_hh = ret_timestamp['hh']
35+
self.ts_mm = ret_timestamp['mm']
36+
self.ts_ss = ret_timestamp['ss']
37+
38+
def __str__(self):
39+
ret = ""
40+
for field, field_dict in self.ret.items():
41+
ret += f"---- {field} ----"
42+
ret += "\n".join("{:<30} {}".format(k, v)
43+
for k, v in field_dict.items())
44+
return ret
45+
46+
def get_temp(self):
47+
return self.temp
48+
49+
def get_gyro(self):
50+
return {'gx': self.gx, 'gy': self.gy, 'gz': self.gz}

Diff for: GroundStationGUI.py

+18-4
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,14 @@ def __init__(self, parent, pipe):
103103
self.parent.after(1000, self.update_beacon_values)
104104

105105
def update_beacon_values(self):
106-
if self.beacon_pipe.poll():
106+
if self.beacon_pipe.poll(timeout=0):
107107
ls = self.beacon_pipe.recv()
108108
temp = ls[0]
109109
gx = ls[1]
110110
gy = ls[2]
111111
gz = ls[3]
112112
self.beacon_frame.update_beacon_values(temp, gx, gy, gz)
113-
self.parent.after(1000, self.update_beacon_values)
113+
self.parent.after(1000, self.update_beacon_values)
114114

115115

116116
class BeaconFrame(tk.LabelFrame):
@@ -121,9 +121,13 @@ def __init__(self, parent, *args, **kwargs):
121121

122122
# Create variable to store beacon values
123123
self.temp = tk.StringVar()
124+
self.temp.set("0.00")
124125
self.gx = tk.StringVar()
126+
self.gx.set("0")
125127
self.gy = tk.StringVar()
128+
self.gy.set("0")
126129
self.gz = tk.StringVar()
130+
self.gz.set("0")
127131

128132
# Create label for beacon data header
129133
self.temperature_label = self._create_header_label("Temp")
@@ -140,14 +144,24 @@ def __init__(self, parent, *args, **kwargs):
140144
# Put the labels in grids with row/col
141145
self._arrange_grid()
142146

143-
self.update_beacon_values("0.0", "0", "0", "0")
144-
145147
def update_beacon_values(self, temp, gx, gy, gz):
148+
def uncolor():
149+
self.temperature_label['bg'] = 'grey94'
150+
self.gx_label['bg'] = 'grey94'
151+
self.gy_label['bg'] = 'grey94'
152+
self.gz_label['bg'] = 'grey94'
153+
146154
self.temp.set(temp)
147155
self.gx.set(gx)
148156
self.gy.set(gy)
149157
self.gz.set(gz)
150158

159+
self.temperature_label['bg'] = 'yellow'
160+
self.gx_label['bg'] = 'yellow'
161+
self.gy_label['bg'] = 'yellow'
162+
self.gz_label['bg'] = 'yellow'
163+
self.parent.after(1200, uncolor)
164+
151165
def _create_header_label(self, header_text):
152166
return tk.Label(self, width=6, text=header_text, borderwidth=1, relief="groove")
153167

Diff for: ccsds_decoder.py

+2-160
Original file line numberDiff line numberDiff line change
@@ -1,167 +1,9 @@
1-
class CCSDS_Parsed_Beacon():
2-
def __init__(self, ret_ttnc, ret_adcs, ret_eps, ret_payload, ret_timestamp):
3-
self.ret = {'TT&C': ret_ttnc, 'ADCS': ret_adcs, 'EPS': ret_eps,
4-
'Payload': ret_payload, 'Timestamp': ret_timestamp}
5-
6-
# Unpack ttnc
7-
self.mode = ret_ttnc['Transmission Mode']
8-
self.baud = ret_ttnc['Baud Rate']
9-
self.channel = ret_ttnc['Channel']
10-
self.tx_power = ret_ttnc['Transmit Power']
11-
12-
# Unpack adcs
13-
self.gx = ret_adcs['gx']
14-
self.gy = ret_adcs['gy']
15-
self.gz = ret_adcs['gz']
16-
self.mx = ret_adcs['mx']
17-
self.my = ret_adcs['my']
18-
self.mz = ret_adcs['mz']
19-
20-
# Unpack eps
21-
self.temp = ret_eps['Temperature']
22-
self.eps_reserved = ret_eps['Reserved']
23-
24-
# Unpack payload
25-
self.r1 = ret_payload['Reserved byte 1']
26-
self.r2 = ret_payload['Reserved byte 2']
27-
self.r3 = ret_payload['Reserved byte 3']
28-
self.r4 = ret_payload['Reserved byte 4']
29-
30-
# Unpack timestamp
31-
self.ts_DD = ret_timestamp['DD']
32-
self.ts_MM = ret_timestamp['MM']
33-
self.ts_YYYY = ret_timestamp['YYYY']
34-
self.ts_hh = ret_timestamp['hh']
35-
self.ts_mm = ret_timestamp['mm']
36-
self.ts_ss = ret_timestamp['ss']
37-
38-
def __str__(self):
39-
ret = ""
40-
for field, field_dict in self.ret.items():
41-
ret += f"---- {field} ----"
42-
ret += "\n".join("{:<30} {}".format(k, v)
43-
for k, v in field_dict.items())
44-
return ret
45-
46-
def get_temp(self):
47-
return self.temp
48-
49-
def get_gyro(self):
50-
return {'gx': self.gx, 'gy': self.gy, 'gz': self.gz}
1+
from CCSDS_Beacon_Decoder import CCSDS_Beacon_Decoder
512

523

534
class CCSDS_Decoder():
54-
def __init___(self):
5+
def __init__(self):
556
self.beacon_decoder = CCSDS_Beacon_Decoder()
567

578
def parse_beacon(self, beacon):
589
return self.beacon_decoder.parse(beacon)
59-
60-
61-
class CCSDS_Beacon_Decoder():
62-
def __init__(self):
63-
pass
64-
65-
def parse(self, packet):
66-
# header = packet[0:6]
67-
# telemetry_packet_type = packet[6]
68-
69-
ttnc_field = packet[7:9]
70-
ret_ttnc = self._parse_ttnc_field(ttnc_field)
71-
72-
adcs_field = packet[9:21]
73-
ret_adcs = self._parse_adcs_field(adcs_field)
74-
75-
eps_field = packet[21:27]
76-
ret_eps = self._parse_eps_field(eps_field)
77-
78-
payload_field = packet[27:31]
79-
ret_payload = self._parse_payload_field(payload_field)
80-
81-
timestamp_field = packet[31:]
82-
ret_timestamp = self._parse_timestamp_field(timestamp_field)
83-
84-
return CCSDS_Parsed_Beacon(ret_ttnc, ret_adcs, ret_eps, ret_payload, ret_timestamp)
85-
86-
def _parse_ttnc_field(self, ttnc_field):
87-
# Decode mode
88-
mode_lookup = {0: 'FU1', 1: 'FU2', 2: 'FU3', 3: 'FU4'}
89-
mode_bits = (ttnc_field[0] & 0b01100000) >> 5
90-
mode = mode_lookup.get(mode_bits)
91-
92-
# Decode baud
93-
baud_lookup = {0: '1200', 1: '2400', 2: '4800', 3: '9600',
94-
4: '19200', 5: '38400', 6: '57600', 7: '115200'}
95-
baud_bits = (ttnc_field[0] & 0b00011100) >> 2
96-
baud = baud_lookup.get(baud_bits)
97-
98-
# Channel
99-
channel_bits = ((ttnc_field[0] & 0b00000011)
100-
<< 5) | (ttnc_field[1] >> 3)
101-
channel = str(int(f'{channel_bits:#0}'))
102-
103-
# Transmit Power
104-
tx_power_lookup = {0: '-1', 1: '2', 2: '5',
105-
3: '8', 4: '11', 5: '14', 6: '17', 7: '20'}
106-
tx_power_bits = (ttnc_field[1] & 0b111)
107-
tx_power = tx_power_lookup.get(tx_power_bits)
108-
109-
ret_ttnc = {'Transmission Mode': mode, 'Baud Rate': baud,
110-
'Channel': channel, 'Transmit Power': tx_power}
111-
return ret_ttnc
112-
113-
def _parse_adcs_field(self, adcs_field):
114-
# Decode gx
115-
gx = int.from_bytes(adcs_field[0:2], byteorder='big', signed=True)
116-
117-
# Decode gy
118-
gy = int.from_bytes(adcs_field[2:4], byteorder='big', signed=True)
119-
120-
# Decode gz
121-
gz = int.from_bytes(adcs_field[4:6], byteorder='big', signed=True)
122-
123-
# Decode mx
124-
mx = int.from_bytes(adcs_field[6:8], byteorder='big', signed=True)
125-
126-
# Decode my
127-
my = int.from_bytes(adcs_field[8:10], byteorder='big', signed=True)
128-
129-
# Decode mz
130-
mz = int.from_bytes(
131-
adcs_field[10:12], byteorder='big', signed=True)
132-
133-
ret_adcs = {'gx': gx, 'gy': gy, 'gz': gz,
134-
'mx': mx, 'my': my, 'mz': mz}
135-
return ret_adcs
136-
137-
def _parse_eps_field(self, eps_field):
138-
temp_int = int.from_bytes(
139-
eps_field[0:3], byteorder='big', signed=True)
140-
temp = temp_int / 100
141-
reserved = int.from_bytes(
142-
eps_field[3:6], byteorder='big', signed=True)
143-
144-
return {'Temperature': temp, 'Reserved': reserved}
145-
146-
def _parse_payload_field(self, payload_field):
147-
r1 = payload_field[0]
148-
r2 = payload_field[1]
149-
r3 = payload_field[2]
150-
r4 = payload_field[3]
151-
152-
ret_payload = {'Reserved byte 1': r1, 'Reserved byte 2': r2,
153-
'Reserved byte 3': r3, 'Reserved byte 4': r4}
154-
return ret_payload
155-
156-
def _parse_timestamp_field(self, timestamp_field):
157-
DD = timestamp_field[0]
158-
MM = timestamp_field[1]
159-
YYYY = int.from_bytes(
160-
timestamp_field[2:4], byteorder='big', signed=False)
161-
hh = timestamp_field[4]
162-
mm = timestamp_field[5]
163-
ss = timestamp_field[6]
164-
165-
ret_timestamp = {"DD": DD, "MM": MM,
166-
"YYYY": YYYY, "hh": hh, "mm": mm, "ss": ss}
167-
return ret_timestamp

0 commit comments

Comments
 (0)