openc3-cosmos-demo 5.11.2 → 5.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/plugin.txt +2 -2
- data/targets/INST/lib/example_limits_response.rb +4 -10
- data/targets/INST/procedures/calendar.rb +43 -0
- data/targets/INST/target.txt +2 -0
- data/targets/INST2/cmd_tlm/_ccsds_cmd.txt +9 -0
- data/targets/INST2/cmd_tlm/_ccsds_tlm.txt +19 -0
- data/targets/INST2/cmd_tlm/inst_cmds.txt +68 -0
- data/targets/INST2/cmd_tlm/inst_tlm.txt +149 -0
- data/targets/INST2/cmd_tlm/inst_tlm_override.txt +12 -0
- data/targets/INST2/data/attitude.bin +0 -0
- data/targets/INST2/data/position.bin +0 -0
- data/targets/INST2/lib/example_limits_response.py +27 -0
- data/targets/INST2/lib/helper.py +3 -0
- data/targets/INST2/lib/sim_inst.py +383 -0
- data/targets/INST2/procedures/calendar.py +57 -0
- data/targets/{INST/procedures_py → INST2/procedures}/checks.py +0 -1
- data/targets/{INST/procedures_py → INST2/procedures}/collect.py +7 -3
- data/targets/{INST/procedures_py → INST2/procedures}/disconnect.py +0 -2
- data/targets/{INST/procedures_py → INST2/procedures}/file_dialog.py +0 -2
- data/targets/{INST/procedures_py → INST2/procedures}/metadata.py +0 -2
- data/targets/INST2/procedures/my_script_suite.py +50 -0
- data/targets/INST2/procedures/my_test_suite.py +43 -0
- data/targets/{INST/procedures_py → INST2/procedures}/screens.py +0 -2
- data/targets/{INST/procedures_py → INST2/procedures}/stash.py +0 -2
- data/targets/{INST/procedures_py → INST2/procedures}/target_file.py +0 -1
- data/targets/{INST/procedures_py → INST2/procedures}/utilities/clear.py +0 -3
- data/targets/{INST/procedures_py → INST2/procedures}/utilities/collect.py +1 -3
- data/targets/INST2/public/ground_error.png +0 -0
- data/targets/INST2/public/ground_off.png +0 -0
- data/targets/INST2/public/ground_on.png +0 -0
- data/targets/INST2/public/satellite.png +0 -0
- data/targets/INST2/public/spiral.jpg +0 -0
- data/targets/INST2/screens/_footer.txt +1 -0
- data/targets/INST2/screens/adcs.txt +65 -0
- data/targets/INST2/screens/array.txt +16 -0
- data/targets/INST2/screens/block.txt +7 -0
- data/targets/INST2/screens/commanding.txt +57 -0
- data/targets/INST2/screens/graphs.txt +27 -0
- data/targets/INST2/screens/ground.txt +48 -0
- data/targets/INST2/screens/hs.txt +41 -0
- data/targets/INST2/screens/image.txt +3 -0
- data/targets/INST2/screens/latest.txt +20 -0
- data/targets/INST2/screens/launcher.txt +10 -0
- data/targets/INST2/screens/limits.txt +77 -0
- data/targets/INST2/screens/other.txt +22 -0
- data/targets/INST2/screens/params.txt +69 -0
- data/targets/INST2/screens/simple.txt +6 -0
- data/targets/INST2/screens/tabs.txt +56 -0
- data/targets/INST2/screens/web.txt +5 -0
- data/targets/INST2/tables/bin/ConfigTables.bin +0 -0
- data/targets/INST2/tables/config/ConfigTables_def.txt +7 -0
- data/targets/INST2/tables/config/MCConfigurationTable_def.txt +36 -0
- data/targets/INST2/tables/config/PPSSelectionTable_def.txt +7 -0
- data/targets/INST2/tables/config/TLMMonitoringTable_def.txt +31 -0
- data/targets/INST2/tables/procedures/download.rb +16 -0
- data/targets/INST2/tables/procedures/upload.rb +19 -0
- data/targets/INST2/target.txt +27 -0
- data/targets/SYSTEM/procedures/example_test.rb +0 -5
- data/tools/widgets/BigWidget/BigWidget.umd.min.js +1 -3
- data/tools/widgets/BigWidget/BigWidget.umd.min.js.map +1 -1
- data/tools/widgets/DataviewerquaternionWidget/DataviewerquaternionWidget.umd.min.js +2 -2
- data/tools/widgets/DataviewerquaternionWidget/DataviewerquaternionWidget.umd.min.js.map +1 -1
- data/tools/widgets/DataviewertimeWidget/DataviewertimeWidget.umd.min.js +1 -1
- data/tools/widgets/DataviewertimeWidget/DataviewertimeWidget.umd.min.js.map +1 -1
- data/tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js +1 -1
- data/tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js.map +1 -1
- metadata +56 -12
@@ -0,0 +1,383 @@
|
|
1
|
+
# Copyright 2023 OpenC3, Inc.
|
2
|
+
# All Rights Reserved.
|
3
|
+
#
|
4
|
+
# This program is free software; you can modify and/or redistribute it
|
5
|
+
# under the terms of the GNU Affero General Public License
|
6
|
+
# as published by the Free Software Foundation; version 3 with
|
7
|
+
# attribution addendums as found in the LICENSE.txt
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# This file may also be used under the terms of a commercial license
|
15
|
+
# if purchased from OpenC3, Inc.
|
16
|
+
|
17
|
+
import os
|
18
|
+
import time
|
19
|
+
import base64
|
20
|
+
import random
|
21
|
+
import threading
|
22
|
+
from io import BytesIO
|
23
|
+
from openc3.utilities.simulated_target import SimulatedTarget
|
24
|
+
from openc3.packets.structure import Structure
|
25
|
+
from openc3.packets.packet import Packet
|
26
|
+
from openc3.system.system import System
|
27
|
+
from openc3.top_level import kill_thread
|
28
|
+
|
29
|
+
|
30
|
+
# Simulated instrument for the demo. Populates several packets and cycles
|
31
|
+
# the telemetry to simulate an active target.
|
32
|
+
class SimInst(SimulatedTarget):
|
33
|
+
SOLAR_PANEL_DFLTS = [-179.0, 179.0, -179.0, 179.0, -95.0]
|
34
|
+
|
35
|
+
def __init__(self, target_name):
|
36
|
+
super().__init__(target_name)
|
37
|
+
|
38
|
+
self.target = System.targets[target_name]
|
39
|
+
position_filename = os.path.join(self.target.dir, "data", "position.bin")
|
40
|
+
attitude_filename = os.path.join(self.target.dir, "data", "attitude.bin")
|
41
|
+
position_data = None
|
42
|
+
with open(position_filename, "rb") as f:
|
43
|
+
position_data = f.read()
|
44
|
+
attitude_data = None
|
45
|
+
with open(attitude_filename, "rb") as f:
|
46
|
+
attitude_data = f.read()
|
47
|
+
self.position_file = BytesIO(position_data)
|
48
|
+
self.position_file_size = len(position_data)
|
49
|
+
self.attitude_file = BytesIO(attitude_data)
|
50
|
+
self.attitude_file_size = len(attitude_data)
|
51
|
+
self.position_file_bytes_read = 0
|
52
|
+
self.attitude_file_bytes_read = 0
|
53
|
+
|
54
|
+
with open(os.path.join(self.target.dir, "public", "spiral.jpg"), "rb") as f:
|
55
|
+
data = f.read()
|
56
|
+
self.image = base64.b64encode(data)
|
57
|
+
|
58
|
+
self.pos_packet = Structure("BIG_ENDIAN")
|
59
|
+
self.pos_packet.append_item("DAY", 16, "UINT")
|
60
|
+
self.pos_packet.append_item("MSOD", 32, "UINT")
|
61
|
+
self.pos_packet.append_item("USOMS", 16, "UINT")
|
62
|
+
self.pos_packet.append_item("POSX", 32, "FLOAT")
|
63
|
+
self.pos_packet.append_item("POSY", 32, "FLOAT")
|
64
|
+
self.pos_packet.append_item("POSZ", 32, "FLOAT")
|
65
|
+
self.pos_packet.append_item("SPARE1", 16, "UINT")
|
66
|
+
self.pos_packet.append_item("SPARE2", 32, "UINT")
|
67
|
+
self.pos_packet.append_item("SPARE3", 16, "UINT")
|
68
|
+
self.pos_packet.append_item("VELX", 32, "FLOAT")
|
69
|
+
self.pos_packet.append_item("VELY", 32, "FLOAT")
|
70
|
+
self.pos_packet.append_item("VELZ", 32, "FLOAT")
|
71
|
+
self.pos_packet.append_item("SPARE4", 32, "UINT")
|
72
|
+
|
73
|
+
self.att_packet = Structure("BIG_ENDIAN")
|
74
|
+
self.att_packet.append_item("DAY", 16, "UINT")
|
75
|
+
self.att_packet.append_item("MSOD", 32, "UINT")
|
76
|
+
self.att_packet.append_item("USOMS", 16, "UINT")
|
77
|
+
self.att_packet.append_item("Q1", 32, "FLOAT")
|
78
|
+
self.att_packet.append_item("Q2", 32, "FLOAT")
|
79
|
+
self.att_packet.append_item("Q3", 32, "FLOAT")
|
80
|
+
self.att_packet.append_item("Q4", 32, "FLOAT")
|
81
|
+
self.att_packet.append_item("BIASX", 32, "FLOAT")
|
82
|
+
self.att_packet.append_item("BIASY", 32, "FLOAT")
|
83
|
+
self.att_packet.append_item("BIASZ", 32, "FLOAT")
|
84
|
+
self.att_packet.append_item("SPARE", 32, "FLOAT")
|
85
|
+
|
86
|
+
packet = self.tlm_packets["HEALTH_STATUS"]
|
87
|
+
packet.write("CcsdsSeqFlags", "NOGROUP")
|
88
|
+
packet.write("CcsdsLength", len(packet.buffer) - 7)
|
89
|
+
packet.write("temp1", 50.0)
|
90
|
+
packet.write("temp2", -20.0)
|
91
|
+
packet.write("temp3", 85.0)
|
92
|
+
packet.write("temp4", 0.0)
|
93
|
+
packet.write("duration", 10.0)
|
94
|
+
packet.write("collects", 0.0)
|
95
|
+
packet.write("collect_type", "NORMAL")
|
96
|
+
|
97
|
+
packet = self.tlm_packets["ADCS"]
|
98
|
+
packet.write("CcsdsSeqFlags", "NOGROUP")
|
99
|
+
packet.write("CcsdsLength", len(packet.buffer) - 7)
|
100
|
+
|
101
|
+
packet = self.tlm_packets["PARAMS"]
|
102
|
+
packet.write("CcsdsSeqFlags", "NOGROUP")
|
103
|
+
packet.write("CcsdsLength", len(packet.buffer) - 7)
|
104
|
+
packet.write("value1", 0)
|
105
|
+
packet.write("value2", 1)
|
106
|
+
packet.write("value3", 2)
|
107
|
+
packet.write("value4", 1)
|
108
|
+
packet.write("value5", 0)
|
109
|
+
|
110
|
+
packet = self.tlm_packets["IMAGE"]
|
111
|
+
packet.write("CcsdsSeqFlags", "NOGROUP")
|
112
|
+
packet.write("CcsdsLength", len(packet.buffer) - 7)
|
113
|
+
|
114
|
+
packet = self.tlm_packets["MECH"]
|
115
|
+
packet.write("CcsdsSeqFlags", "NOGROUP")
|
116
|
+
packet.write("CcsdsLength", len(packet.buffer) - 7)
|
117
|
+
|
118
|
+
self.solar_panel_positions = SimInst.SOLAR_PANEL_DFLTS[:]
|
119
|
+
self.solar_panel_thread = None
|
120
|
+
self.solar_panel_thread_cancel = False
|
121
|
+
|
122
|
+
self.trackStars = list(range(10))
|
123
|
+
self.trackStars[0] = 1237
|
124
|
+
self.trackStars[1] = 1329
|
125
|
+
self.trackStars[2] = 1333
|
126
|
+
self.trackStars[3] = 1139
|
127
|
+
self.trackStars[4] = 1161
|
128
|
+
self.trackStars[5] = 682
|
129
|
+
self.trackStars[6] = 717
|
130
|
+
self.trackStars[7] = 814
|
131
|
+
self.trackStars[8] = 583
|
132
|
+
self.trackStars[9] = 622
|
133
|
+
|
134
|
+
self.bad_temp2 = False
|
135
|
+
self.last_temp2 = 0
|
136
|
+
self.quiet = False
|
137
|
+
self.time_offset = 0
|
138
|
+
|
139
|
+
def set_rates(self):
|
140
|
+
self.set_rate("ADCS", 10)
|
141
|
+
self.set_rate("HEALTH_STATUS", 100)
|
142
|
+
self.set_rate("PARAMS", 100)
|
143
|
+
self.set_rate("IMAGE", 100)
|
144
|
+
self.set_rate("MECH", 10)
|
145
|
+
|
146
|
+
def tick_period_seconds(self):
|
147
|
+
return 0.1 # Override this method to optimize
|
148
|
+
|
149
|
+
def tick_increment(self):
|
150
|
+
return 10 # Override this method to optimize
|
151
|
+
|
152
|
+
def write(self, packet):
|
153
|
+
name = packet.packet_name.upper()
|
154
|
+
|
155
|
+
hs_packet = self.tlm_packets["HEALTH_STATUS"]
|
156
|
+
params_packet = self.tlm_packets["PARAMS"]
|
157
|
+
|
158
|
+
match name:
|
159
|
+
case "COLLECT":
|
160
|
+
hs_packet.write("collects", hs_packet.read("collects") + 1)
|
161
|
+
hs_packet.write("duration", packet.read("duration"))
|
162
|
+
hs_packet.write("collect_type", packet.read("type"))
|
163
|
+
case "CLEAR":
|
164
|
+
hs_packet.write("collects", 0)
|
165
|
+
case "MEMLOAD":
|
166
|
+
hs_packet.write("blocktest", packet.read("data"))
|
167
|
+
case "QUIET":
|
168
|
+
if packet.read("state") == "TRUE":
|
169
|
+
self.quiet = True
|
170
|
+
else:
|
171
|
+
self.quiet = False
|
172
|
+
case "TIME_OFFSET":
|
173
|
+
self.time_offset = packet.read("seconds")
|
174
|
+
case "SETPARAMS":
|
175
|
+
params_packet.write("value1", packet.read("value1"))
|
176
|
+
params_packet.write("value2", packet.read("value2"))
|
177
|
+
params_packet.write("value3", packet.read("value3"))
|
178
|
+
params_packet.write("value4", packet.read("value4"))
|
179
|
+
params_packet.write("value5", packet.read("value5"))
|
180
|
+
case "ASCIICMD":
|
181
|
+
hs_packet.write("asciicmd", packet.read("string"))
|
182
|
+
case "SLRPNLDEPLOY":
|
183
|
+
if self.solar_panel_thread and self.solar_panel_thread.is_alive():
|
184
|
+
return
|
185
|
+
self.solar_panel_thread = threading.Thread(
|
186
|
+
target=self.solar_panel_thread_method
|
187
|
+
)
|
188
|
+
self.solar_panel_thread.start()
|
189
|
+
case "SLRPNLRESET":
|
190
|
+
kill_thread(self, self.solar_panel_thread)
|
191
|
+
self.solar_panel_positions = SimInst.SOLAR_PANEL_DFLTS[:]
|
192
|
+
|
193
|
+
def solar_panel_thread_method(self):
|
194
|
+
self.solar_panel_thread_cancel = False
|
195
|
+
for i in reversed(self.solar_panel_positions):
|
196
|
+
while (self.solar_panel_positions[i] > 0.1) or (
|
197
|
+
self.solar_panel_positions[i] < -0.1
|
198
|
+
):
|
199
|
+
if self.solar_panel_positions[i] > 3.0:
|
200
|
+
self.solar_panel_positions[i] -= 3.0
|
201
|
+
elif self.solar_panel_positions[i] < -3.0:
|
202
|
+
self.solar_panel_positions[i] += 3.0
|
203
|
+
else:
|
204
|
+
self.solar_panel_positions[i] = 0.0
|
205
|
+
time.sleep(0.10)
|
206
|
+
if self.solar_panel_thread_cancel:
|
207
|
+
break
|
208
|
+
if self.solar_panel_thread_cancel:
|
209
|
+
self.solar_panel_thread_cancel = False
|
210
|
+
break
|
211
|
+
|
212
|
+
def graceful_kill(self):
|
213
|
+
self.solar_panel_thread_cancel = True
|
214
|
+
|
215
|
+
def read(self, count_100hz, time):
|
216
|
+
pending_packets = self.get_pending_packets(count_100hz)
|
217
|
+
|
218
|
+
for packet in pending_packets:
|
219
|
+
match packet.packet_name:
|
220
|
+
case "ADCS":
|
221
|
+
# Read 44 Bytes for Position Data
|
222
|
+
pos_data = None
|
223
|
+
try:
|
224
|
+
pos_data = self.position_file.read(44)
|
225
|
+
self.position_file_bytes_read += 44
|
226
|
+
except OSError:
|
227
|
+
pass # Do Nothing
|
228
|
+
|
229
|
+
if pos_data is None or len(pos_data) == 0:
|
230
|
+
# Assume end of file - close and reopen
|
231
|
+
self.position_file.seek(0)
|
232
|
+
pos_data = self.position_file.read(44)
|
233
|
+
self.position_file_bytes_read = 44
|
234
|
+
|
235
|
+
self.pos_packet.buffer = pos_data
|
236
|
+
packet.write("posx", self.pos_packet.read("posx"))
|
237
|
+
packet.write("posy", self.pos_packet.read("posy"))
|
238
|
+
packet.write("posz", self.pos_packet.read("posz"))
|
239
|
+
packet.write("velx", self.pos_packet.read("velx"))
|
240
|
+
packet.write("vely", self.pos_packet.read("vely"))
|
241
|
+
packet.write("velz", self.pos_packet.read("velz"))
|
242
|
+
|
243
|
+
# Read 40 Bytes for Attitude Data
|
244
|
+
att_data = None
|
245
|
+
try:
|
246
|
+
att_data = self.attitude_file.read(40)
|
247
|
+
self.attitude_file_bytes_read += 40
|
248
|
+
except OSError:
|
249
|
+
pass # Do Nothing
|
250
|
+
|
251
|
+
if att_data is None or len(att_data) == 0:
|
252
|
+
self.attitude_file.seek(0)
|
253
|
+
att_data = self.attitude_file.read(40)
|
254
|
+
self.attitude_file_bytes_read = 40
|
255
|
+
|
256
|
+
self.att_packet.buffer = att_data
|
257
|
+
packet.write("q1", self.att_packet.read("q1"))
|
258
|
+
packet.write("q2", self.att_packet.read("q2"))
|
259
|
+
packet.write("q3", self.att_packet.read("q3"))
|
260
|
+
packet.write("q4", self.att_packet.read("q4"))
|
261
|
+
packet.write("biasx", self.att_packet.read("biasx"))
|
262
|
+
packet.write("biasy", self.att_packet.read("biasy"))
|
263
|
+
packet.write("biasy", self.att_packet.read("biasz"))
|
264
|
+
|
265
|
+
packet.write(
|
266
|
+
"star1id", self.trackStars[(int(count_100hz / 100) + 0) % 10]
|
267
|
+
)
|
268
|
+
packet.write(
|
269
|
+
"star2id", self.trackStars[(int(count_100hz / 100) + 1) % 10]
|
270
|
+
)
|
271
|
+
packet.write(
|
272
|
+
"star3id", self.trackStars[(int(count_100hz / 100) + 2) % 10]
|
273
|
+
)
|
274
|
+
packet.write(
|
275
|
+
"star4id", self.trackStars[(int(count_100hz / 100) + 3) % 10]
|
276
|
+
)
|
277
|
+
packet.write(
|
278
|
+
"star5id", self.trackStars[(int(count_100hz / 100) + 4) % 10]
|
279
|
+
)
|
280
|
+
|
281
|
+
packet.write(
|
282
|
+
"posprogress",
|
283
|
+
(
|
284
|
+
float(self.position_file_bytes_read)
|
285
|
+
/ float(self.position_file_size)
|
286
|
+
)
|
287
|
+
* 100.0,
|
288
|
+
)
|
289
|
+
packet.write(
|
290
|
+
"attprogress",
|
291
|
+
(
|
292
|
+
float(self.attitude_file_bytes_read)
|
293
|
+
/ float(self.attitude_file_size)
|
294
|
+
)
|
295
|
+
* 100.0,
|
296
|
+
)
|
297
|
+
|
298
|
+
packet.write("timesec", int(time - self.time_offset))
|
299
|
+
packet.write("timeus", int((time % 1) * 1000000))
|
300
|
+
packet.write("ccsdsseqcnt", packet.read("ccsdsseqcnt") + 1)
|
301
|
+
|
302
|
+
case "HEALTH_STATUS":
|
303
|
+
if self.quiet:
|
304
|
+
self.bad_temp2 = False
|
305
|
+
self.cycle_tlm_item(packet, "temp1", -15.0, 15.0, 5.0)
|
306
|
+
self.cycle_tlm_item(packet, "temp2", -50.0, 25.0, -1.0)
|
307
|
+
self.cycle_tlm_item(packet, "temp3", 0.0, 50.0, 2.0)
|
308
|
+
else:
|
309
|
+
self.cycle_tlm_item(packet, "temp1", -95.0, 95.0, 5.0)
|
310
|
+
if self.bad_temp2:
|
311
|
+
packet.write("temp2", self.last_temp2)
|
312
|
+
self.bad_temp2 = False
|
313
|
+
self.last_temp2 = self.cycle_tlm_item(
|
314
|
+
packet, "temp2", -50.0, 50.0, -1.0
|
315
|
+
)
|
316
|
+
if abs(abs(packet.read("temp2")) - 30) < 2:
|
317
|
+
packet.write("temp2", float("nan"))
|
318
|
+
self.bad_temp2 = True
|
319
|
+
elif abs(abs(packet.read("temp2")) - 20) < 2:
|
320
|
+
packet.write("temp2", float("-inf"))
|
321
|
+
self.bad_temp2 = True
|
322
|
+
elif abs(abs(packet.read("temp2")) - 10) < 2:
|
323
|
+
packet.write("temp2", float("inf"))
|
324
|
+
self.bad_temp2 = True
|
325
|
+
self.cycle_tlm_item(packet, "temp3", -30.0, 80.0, 2.0)
|
326
|
+
self.cycle_tlm_item(packet, "temp4", 0.0, 20.0, -0.1)
|
327
|
+
|
328
|
+
packet.write("timesec", int(time - self.time_offset))
|
329
|
+
packet.write("timeus", int((time % 1) * 1000000))
|
330
|
+
packet.write("ccsdsseqcnt", packet.read("ccsdsseqcnt") + 1)
|
331
|
+
|
332
|
+
ary = []
|
333
|
+
for index in range(0, 10):
|
334
|
+
ary.append(index)
|
335
|
+
packet.write("ary", ary)
|
336
|
+
|
337
|
+
if self.quiet:
|
338
|
+
packet.write("ground1status", "CONNECTED")
|
339
|
+
packet.write("ground2status", "CONNECTED")
|
340
|
+
else:
|
341
|
+
if count_100hz % 1000 == 0:
|
342
|
+
if packet.read("ground1status") == "CONNECTED":
|
343
|
+
packet.write("ground1status", "UNAVAILABLE")
|
344
|
+
else:
|
345
|
+
packet.write("ground1status", "CONNECTED")
|
346
|
+
|
347
|
+
if count_100hz % 500 == 0:
|
348
|
+
if packet.read("ground2status") == "CONNECTED":
|
349
|
+
packet.write("ground2status", "UNAVAILABLE")
|
350
|
+
else:
|
351
|
+
packet.write("ground2status", "CONNECTED")
|
352
|
+
|
353
|
+
case "PARAMS":
|
354
|
+
packet.write("timesec", int(time - self.time_offset))
|
355
|
+
packet.write("timeus", int((time % 1) * 1000000))
|
356
|
+
packet.write("ccsdsseqcnt", packet.read("ccsdsseqcnt") + 1)
|
357
|
+
|
358
|
+
case "IMAGE":
|
359
|
+
packet.write("timesec", int(time - self.time_offset))
|
360
|
+
packet.write("timeus", int((time % 1) * 1000000))
|
361
|
+
packet.write("image", self.image)
|
362
|
+
# Create an Array of random bytes
|
363
|
+
packet.write("block", random.randbytes(1000))
|
364
|
+
packet.write("ccsdsseqcnt", packet.read("ccsdsseqcnt") + 1)
|
365
|
+
|
366
|
+
case "MECH":
|
367
|
+
packet.write("timesec", int(time - self.time_offset))
|
368
|
+
packet.write("timeus", int((time % 1) * 1000000))
|
369
|
+
packet.write("ccsdsseqcnt", packet.read("ccsdsseqcnt") + 1)
|
370
|
+
packet.write("slrpnl1", self.solar_panel_positions[0])
|
371
|
+
packet.write("slrpnl2", self.solar_panel_positions[1])
|
372
|
+
packet.write("slrpnl3", self.solar_panel_positions[2])
|
373
|
+
packet.write("slrpnl4", self.solar_panel_positions[3])
|
374
|
+
packet.write("slrpnl5", self.solar_panel_positions[4])
|
375
|
+
packet.write("current", 0.5)
|
376
|
+
|
377
|
+
# Every 10s throw an unknown packet at the server just to demo that
|
378
|
+
if count_100hz % 1000 == 900:
|
379
|
+
pending_packets.append(
|
380
|
+
Packet(None, None, "BIG_ENDIAN", None, random.randbytes(10))
|
381
|
+
)
|
382
|
+
|
383
|
+
return pending_packets
|
@@ -0,0 +1,57 @@
|
|
1
|
+
from datetime import datetime, timezone, timedelta
|
2
|
+
|
3
|
+
tl = create_timeline("Mine")
|
4
|
+
print(
|
5
|
+
tl
|
6
|
+
) # => {"name":"Mine", "color":"#ae2d1b", "scope":"DEFAULT", "updated_at":1698763720728596964}
|
7
|
+
tls = list_timelines()
|
8
|
+
print(tls)
|
9
|
+
print(type(tls))
|
10
|
+
check_expression(f"{len(tls)} == 1")
|
11
|
+
print(
|
12
|
+
tls[0]
|
13
|
+
) # => {"name":"Mine", "color":"#ae2d1b", "scope":"DEFAULT", "updated_at":1698763720728596964}
|
14
|
+
delete_timeline("Mine")
|
15
|
+
check_expression(f"{len(list_timelines())} == 0")
|
16
|
+
|
17
|
+
create_timeline("Mine")
|
18
|
+
set_timeline_color("Mine", "#4287f5")
|
19
|
+
print(
|
20
|
+
get_timeline("Mine")
|
21
|
+
) # => {"name":"Mine", "color":"#4287f5", "scope":"DEFAULT", "updated_at":1698763720728596964}
|
22
|
+
|
23
|
+
now = datetime.now(timezone.utc)
|
24
|
+
start = datetime(now.year, now.month, now.day, now.hour + 1, 30, 00, 00, timezone.utc)
|
25
|
+
stop = start + timedelta(hours=1) # Stop plus 1hr
|
26
|
+
act = create_timeline_activity("Mine", kind="reserve", start=start, stop=stop)
|
27
|
+
print(act) # =>
|
28
|
+
# { "name"=>"Mine", "updated_at"=>1698763721927799173, "fulfillment"=>false, "duration"=>3600,
|
29
|
+
# "start"=>1698764400, "stop"=>1698768000, "kind"=>"reserve",
|
30
|
+
# "events"=>[{"time"=>1698763721, "event"=>"created"}], "data"=>{"username"=>""} }
|
31
|
+
# Get activities in the past ... should be none
|
32
|
+
tlas = get_timeline_activities("Mine", start=start - timedelta(hours=2), stop=now)
|
33
|
+
print(tlas)
|
34
|
+
print(type(tlas))
|
35
|
+
check_expression(f"{len(tlas)} == 0")
|
36
|
+
# Get all activities
|
37
|
+
tlas = get_timeline_activities("Mine")
|
38
|
+
check_expression(f"{len(tlas)} == 1")
|
39
|
+
|
40
|
+
# Create and delete a new activity
|
41
|
+
start = start + timedelta(hours=2)
|
42
|
+
stop = start + timedelta(minutes=30)
|
43
|
+
act = create_timeline_activity("Mine", kind="reserve", start=start, stop=stop)
|
44
|
+
tlas = get_timeline_activities("Mine")
|
45
|
+
check_expression(f"{len(tlas)} == 2")
|
46
|
+
delete_timeline_activity("Mine", act["start"])
|
47
|
+
tlas = get_timeline_activities("Mine")
|
48
|
+
check_expression(f"{len(tlas)} == 1")
|
49
|
+
|
50
|
+
# delete fails since the timeline has activities
|
51
|
+
delete_timeline(
|
52
|
+
"Mine"
|
53
|
+
) #: RuntimeError : Failed to delete timeline due to timeline contains activities, must force remove
|
54
|
+
# Force delete since the timeline has activities
|
55
|
+
delete_timeline("Mine", force=True)
|
56
|
+
tls = list_timelines()
|
57
|
+
check_expression(f"{len(tls)} == 0")
|
@@ -1,7 +1,11 @@
|
|
1
|
-
|
1
|
+
# Instrument code to display line-by-line in Script Runner
|
2
|
+
load_utility("<%= target_name %>/procedures/utilities/collect.py")
|
3
|
+
load_utility("<%= target_name %>/procedures/utilities/clear.py")
|
4
|
+
# Load a target file library (not instrumented)
|
5
|
+
from INST2.lib.helper import Helper
|
2
6
|
|
3
|
-
|
4
|
-
|
7
|
+
helper = Helper()
|
8
|
+
helper.help()
|
5
9
|
|
6
10
|
number = ask("Enter a number.")
|
7
11
|
if not isinstance(number, (int, float)):
|
@@ -0,0 +1,50 @@
|
|
1
|
+
from openc3.script.exceptions import *
|
2
|
+
from openc3.script.suite import Group, Suite
|
3
|
+
|
4
|
+
load_utility("INST/procedures/utilities/clear.py")
|
5
|
+
|
6
|
+
|
7
|
+
class ExampleGroup(Group):
|
8
|
+
def setup(self):
|
9
|
+
print("Setup")
|
10
|
+
|
11
|
+
def script_run_method_with_long_name(self):
|
12
|
+
print(
|
13
|
+
f"Running {Group.current_suite()}:{Group.current_group()}:{Group.current_script()}"
|
14
|
+
)
|
15
|
+
Group.puts("This test verifies requirement 1")
|
16
|
+
raise RuntimeError("error")
|
17
|
+
print("continue past raise") # NOSONAR
|
18
|
+
|
19
|
+
def script_2(self):
|
20
|
+
print(
|
21
|
+
f"Running {Group.current_suite()}:{Group.current_group()}:{Group.current_script()}"
|
22
|
+
)
|
23
|
+
Group.puts("This test verifies requirement 2")
|
24
|
+
self.helper()
|
25
|
+
wait(2)
|
26
|
+
|
27
|
+
def script_3(self):
|
28
|
+
print(
|
29
|
+
f"Running {Group.current_suite()}:{Group.current_group()}:{Group.current_script()}"
|
30
|
+
)
|
31
|
+
raise SkipScript
|
32
|
+
|
33
|
+
def helper(self):
|
34
|
+
if openc3.script.RUNNING_SCRIPT and openc3.script.RUNNING_SCRIPT.manual:
|
35
|
+
answer = ask("Are you sure?")
|
36
|
+
else:
|
37
|
+
answer = "y"
|
38
|
+
|
39
|
+
def teardown(self):
|
40
|
+
print("teardown")
|
41
|
+
|
42
|
+
|
43
|
+
class MySuite(Suite):
|
44
|
+
def __init__(self):
|
45
|
+
super().__init__()
|
46
|
+
self.add_group(ExampleGroup)
|
47
|
+
|
48
|
+
|
49
|
+
print("Running")
|
50
|
+
MySuite().run()
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from openc3.tools.test_runner.test import Test, TestSuite, SkipTestCase
|
2
|
+
|
3
|
+
|
4
|
+
class ExampleTest(Test):
|
5
|
+
def setup(self):
|
6
|
+
print("Setup")
|
7
|
+
|
8
|
+
def test_case_with_long_name(self):
|
9
|
+
print(
|
10
|
+
f"Running {Test.current_test_suite()}:{Test.current_test()}:{Test.current_test_case()}"
|
11
|
+
)
|
12
|
+
Test.puts("This test verifies requirement 1")
|
13
|
+
raise RuntimeError("error")
|
14
|
+
print("continue past raise") # NOSONAR
|
15
|
+
|
16
|
+
def test_2(self):
|
17
|
+
print(
|
18
|
+
f"Running {Test.current_test_suite()}:{Test.current_test()}:{Test.current_test_case()}"
|
19
|
+
)
|
20
|
+
Test.puts("This test verifies requirement 2")
|
21
|
+
self.helper()
|
22
|
+
wait(2)
|
23
|
+
|
24
|
+
def test_3(self):
|
25
|
+
print(
|
26
|
+
f"Running {Test.current_test_suite()}:{Test.current_test()}:{Test.current_test_case()}"
|
27
|
+
)
|
28
|
+
raise SkipTestCase
|
29
|
+
|
30
|
+
def helper(self):
|
31
|
+
if openc3.script.RUNNING_SCRIPT and openc3.script.RUNNING_SCRIPT.manual:
|
32
|
+
answer = ask("Are you sure?")
|
33
|
+
else:
|
34
|
+
answer = "y"
|
35
|
+
|
36
|
+
def teardown(self):
|
37
|
+
print("teardown")
|
38
|
+
|
39
|
+
|
40
|
+
class MyTestSuite(TestSuite):
|
41
|
+
def __init__(self):
|
42
|
+
super().__init__()
|
43
|
+
self.add_test(ExampleTest)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
LABELVALUE <%= target_name %> HEALTH_STATUS PACKET_TIMEFORMATTED WITH_UNITS 30
|