openc3-cosmos-demo 5.11.3 → 5.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/plugin.txt +2 -2
  3. data/targets/INST/lib/example_limits_response.rb +4 -10
  4. data/targets/INST/procedures/calendar.rb +43 -0
  5. data/targets/INST/screens/adcs.txt +12 -12
  6. data/targets/INST/screens/array.txt +5 -9
  7. data/targets/INST/screens/ground.txt +2 -3
  8. data/targets/INST/screens/hs.txt +7 -11
  9. data/targets/INST/target.txt +2 -0
  10. data/targets/INST2/cmd_tlm/_ccsds_cmd.txt +9 -0
  11. data/targets/INST2/cmd_tlm/_ccsds_tlm.txt +19 -0
  12. data/targets/INST2/cmd_tlm/inst_cmds.txt +68 -0
  13. data/targets/INST2/cmd_tlm/inst_tlm.txt +149 -0
  14. data/targets/INST2/cmd_tlm/inst_tlm_override.txt +12 -0
  15. data/targets/INST2/data/attitude.bin +0 -0
  16. data/targets/INST2/data/position.bin +0 -0
  17. data/targets/INST2/lib/example_limits_response.py +27 -0
  18. data/targets/INST2/lib/helper.py +3 -0
  19. data/targets/INST2/lib/sim_inst.py +383 -0
  20. data/targets/INST2/procedures/calendar.py +57 -0
  21. data/targets/{INST/procedures_py → INST2/procedures}/checks.py +0 -1
  22. data/targets/{INST/procedures_py → INST2/procedures}/collect.py +7 -3
  23. data/targets/{INST/procedures_py → INST2/procedures}/disconnect.py +0 -2
  24. data/targets/{INST/procedures_py → INST2/procedures}/file_dialog.py +0 -2
  25. data/targets/{INST/procedures_py → INST2/procedures}/metadata.py +0 -2
  26. data/targets/INST2/procedures/my_script_suite.py +49 -0
  27. data/targets/INST2/procedures/my_test_suite.py +43 -0
  28. data/targets/{INST/procedures_py → INST2/procedures}/screens.py +0 -2
  29. data/targets/{INST/procedures_py → INST2/procedures}/stash.py +0 -2
  30. data/targets/{INST/procedures_py → INST2/procedures}/target_file.py +0 -1
  31. data/targets/{INST/procedures_py → INST2/procedures}/utilities/clear.py +0 -3
  32. data/targets/{INST/procedures_py → INST2/procedures}/utilities/collect.py +1 -3
  33. data/targets/INST2/public/ground_error.png +0 -0
  34. data/targets/INST2/public/ground_off.png +0 -0
  35. data/targets/INST2/public/ground_on.png +0 -0
  36. data/targets/INST2/public/satellite.png +0 -0
  37. data/targets/INST2/public/spiral.jpg +0 -0
  38. data/targets/INST2/screens/_footer.txt +1 -0
  39. data/targets/INST2/screens/adcs.txt +65 -0
  40. data/targets/INST2/screens/array.txt +12 -0
  41. data/targets/INST2/screens/block.txt +7 -0
  42. data/targets/INST2/screens/commanding.txt +57 -0
  43. data/targets/INST2/screens/graphs.txt +27 -0
  44. data/targets/INST2/screens/ground.txt +47 -0
  45. data/targets/INST2/screens/hs.txt +37 -0
  46. data/targets/INST2/screens/image.txt +3 -0
  47. data/targets/INST2/screens/latest.txt +20 -0
  48. data/targets/INST2/screens/launcher.txt +10 -0
  49. data/targets/INST2/screens/limits.txt +77 -0
  50. data/targets/INST2/screens/other.txt +22 -0
  51. data/targets/INST2/screens/params.txt +69 -0
  52. data/targets/INST2/screens/simple.txt +6 -0
  53. data/targets/INST2/screens/tabs.txt +56 -0
  54. data/targets/INST2/screens/web.txt +5 -0
  55. data/targets/INST2/tables/bin/ConfigTables.bin +0 -0
  56. data/targets/INST2/tables/config/ConfigTables_def.txt +7 -0
  57. data/targets/INST2/tables/config/MCConfigurationTable_def.txt +36 -0
  58. data/targets/INST2/tables/config/PPSSelectionTable_def.txt +7 -0
  59. data/targets/INST2/tables/config/TLMMonitoringTable_def.txt +31 -0
  60. data/targets/INST2/tables/procedures/download.rb +16 -0
  61. data/targets/INST2/tables/procedures/upload.rb +19 -0
  62. data/targets/INST2/target.txt +27 -0
  63. data/targets/SYSTEM/procedures/example_test.rb +0 -5
  64. data/targets/SYSTEM/procedures/openc3_api_test.rb +6 -6
  65. data/tools/widgets/BigWidget/BigWidget.umd.min.js +1 -3
  66. data/tools/widgets/BigWidget/BigWidget.umd.min.js.map +1 -1
  67. data/tools/widgets/DataviewerquaternionWidget/DataviewerquaternionWidget.umd.min.js +2 -2
  68. data/tools/widgets/DataviewerquaternionWidget/DataviewerquaternionWidget.umd.min.js.map +1 -1
  69. data/tools/widgets/DataviewertimeWidget/DataviewertimeWidget.umd.min.js +1 -1
  70. data/tools/widgets/DataviewertimeWidget/DataviewertimeWidget.umd.min.js.map +1 -1
  71. data/tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js +1 -1
  72. data/tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js.map +1 -1
  73. 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,5 +1,4 @@
1
1
  import os
2
- from openc3.script import *
3
2
 
4
3
  # Display the environment variables
5
4
  print(os.environ.items())
@@ -1,7 +1,11 @@
1
- from openc3.script import *
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
- load_utility("<%= target_name %>/procedures_py/utilities/collect.py")
4
- load_utility("<%= target_name %>/procedures_py/utilities/clear.py")
7
+ helper = Helper()
8
+ helper.help()
5
9
 
6
10
  number = ask("Enter a number.")
7
11
  if not isinstance(number, (int, float)):
@@ -1,5 +1,3 @@
1
- from openc3.script import *
2
-
3
1
  cmd("<%= target_name %> ABORT")
4
2
  cmd_no_range_check("<%= target_name %> COLLECT with TYPE NORMAL, TEMP 100")
5
3
  cmd_no_hazardous_check("<%= target_name %> CLEAR")
@@ -1,5 +1,3 @@
1
- from openc3.script import *
2
-
3
1
  # Specify the title and message and filter to txt files
4
2
  file = open_file_dialog(
5
3
  "Open a single file", "Choose something interesting", filter=".txt"
@@ -1,5 +1,3 @@
1
- from openc3.script import *
2
-
3
1
  # Example of using metadata. Note each call to metadata_set creates a new entry.
4
2
  # metadata_update without a start time will update the latest metadata entry.
5
3
  print(metadata_get())
@@ -0,0 +1,49 @@
1
+ from openc3.script.suite import Group, Suite
2
+
3
+ load_utility("INST2/procedures/utilities/clear.py")
4
+
5
+
6
+ class ExampleGroup(Group):
7
+ def setup(self):
8
+ print("Setup")
9
+
10
+ def script_run_method_with_long_name(self):
11
+ print(
12
+ f"Running {Group.current_suite()}:{Group.current_group()}:{Group.current_script()}"
13
+ )
14
+ Group.print("This test verifies requirement 1")
15
+ raise RuntimeError("error")
16
+ print("continue past raise") # NOSONAR
17
+
18
+ def script_2(self):
19
+ print(
20
+ f"Running {Group.current_suite()}:{Group.current_group()}:{Group.current_script()}"
21
+ )
22
+ Group.print("This test verifies requirement 2")
23
+ self.helper()
24
+ wait(2)
25
+
26
+ def script_3(self):
27
+ print(
28
+ f"Running {Group.current_suite()}:{Group.current_group()}:{Group.current_script()}"
29
+ )
30
+ raise SkipScript
31
+
32
+ def helper(self):
33
+ if openc3.script.RUNNING_SCRIPT and openc3.script.RUNNING_SCRIPT.manual:
34
+ answer = ask("Are you sure?")
35
+ else:
36
+ answer = "y"
37
+
38
+ def teardown(self):
39
+ print("teardown")
40
+
41
+
42
+ class MySuite(Suite):
43
+ def __init__(self):
44
+ super().__init__()
45
+ self.add_group(ExampleGroup)
46
+
47
+
48
+ print("Running")
49
+ 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.print("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.print("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)
@@ -1,5 +1,3 @@
1
- from openc3.script import *
2
-
3
1
  all_screens = get_screen_list()
4
2
  print(all_screens["INST"])
5
3
  wait(1)
@@ -1,5 +1,3 @@
1
- from openc3.script import *
2
-
3
1
  # Stash API is useful for storing simple key/value pairs
4
2
  # to preserve state between script runs
5
3
  stash_set("key1", "val1")
@@ -1,4 +1,3 @@
1
- from openc3.script import *
2
1
  from openc3.utilities.string import formatted
3
2
  import tempfile
4
3
 
@@ -1,6 +1,3 @@
1
- from openc3.script import *
2
-
3
-
4
1
  def clear():
5
2
  # Command the collect
6
3
  cmd("<%= target_name %> CLEAR")
@@ -1,6 +1,4 @@
1
- from openc3.script import *
2
-
3
- load_utility("<%= target_name %>/procedures_py/utilities/clear.py")
1
+ load_utility("<%= target_name %>/procedures/utilities/clear.py")
4
2
 
5
3
 
6
4
  def collect(type, duration, call_clear=False):
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ LABELVALUE <%= target_name %> HEALTH_STATUS PACKET_TIMEFORMATTED WITH_UNITS 30