openc3-cosmos-script-engine-cstol 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/cstol_script_engine.py +118 -49
- data/public/store_img.png +0 -0
- metadata +13 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d0e4ae051329106a645f8cfafc4692be99ada07d577dc4bdef50b5f8a017c26
|
|
4
|
+
data.tar.gz: 4a8728bf65623019a3f525ed1bcb7527865d927fcbcf1a8b14dd62d1e63f2bb2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e992d06108e1e8c401cb3be499f3fac0da9e3f4a0b94139099a486ffbe7906be2b508654ab4dab7c9a4f2c7dc40f1f8794ce0ca84be4c7bd9648ac3c5227fc8a
|
|
7
|
+
data.tar.gz: d4688f23af1f74ba8969981105cb841cf0064e175e48825f33a460a54ed6559c84f80c4e1cb1209fd8aa147ef60a0ede414b3d8367c138de6b55adf0333d9071
|
data/lib/cstol_script_engine.py
CHANGED
|
@@ -25,12 +25,18 @@ import shlex
|
|
|
25
25
|
import datetime
|
|
26
26
|
import math
|
|
27
27
|
import os
|
|
28
|
-
from openc3.script.exceptions import CheckError,
|
|
28
|
+
from openc3.script.exceptions import CheckError, StopScriptError
|
|
29
29
|
from openc3.script_engines.script_engine import ScriptEngine
|
|
30
30
|
from openc3.script import wait, wait_expression, ask_string, clear_screen, clear_all_screens, set_tlm, display_screen, \
|
|
31
31
|
connect_interface, disconnect_interface, send_raw, start, cmd, get_target_file, tlm, ask_string, set_line_delay, step_mode, run_mode
|
|
32
32
|
|
|
33
33
|
class CstolVariables:
|
|
34
|
+
# NOTE: special_variables is INTENTIONALLY a class-level (shared) dictionary.
|
|
35
|
+
# Special variables ($$ variables) are global to the engine and must persist
|
|
36
|
+
# across every script run and every CstolVariables instance. Unlike
|
|
37
|
+
# local_variables (which __init__ resets per instance), this state is meant to
|
|
38
|
+
# be shared by all instances. Do NOT move this into __init__ or copy it per
|
|
39
|
+
# instance - that would break the intended global behavior.
|
|
34
40
|
special_variables = {
|
|
35
41
|
"$$OWLT": 0.0,
|
|
36
42
|
"$$ERROR": "NO_ERROR",
|
|
@@ -43,8 +49,23 @@ class CstolVariables:
|
|
|
43
49
|
|
|
44
50
|
def __init__(self):
|
|
45
51
|
self.local_variables = {}
|
|
52
|
+
self.if_stack = []
|
|
46
53
|
self.loop_stack = []
|
|
47
54
|
|
|
55
|
+
def set_local_variable(self, name, value):
|
|
56
|
+
"""
|
|
57
|
+
Sets a local variable. Variable names are case insensitive, so they are
|
|
58
|
+
normalized to upper case before being stored.
|
|
59
|
+
"""
|
|
60
|
+
self.local_variables[name.upper()] = value
|
|
61
|
+
|
|
62
|
+
def get_local_variable(self, name):
|
|
63
|
+
"""
|
|
64
|
+
Gets a local variable by name (case insensitive).
|
|
65
|
+
Returns None if the variable does not exist.
|
|
66
|
+
"""
|
|
67
|
+
return self.local_variables.get(name.upper(), None)
|
|
68
|
+
|
|
48
69
|
def set_special_variable(self, name, value):
|
|
49
70
|
"""
|
|
50
71
|
Sets a special variable, which is a variable that starts with '$$'.
|
|
@@ -52,8 +73,9 @@ class CstolVariables:
|
|
|
52
73
|
"""
|
|
53
74
|
if not name.startswith('$$'):
|
|
54
75
|
raise ValueError(f"Special variable names must start with '$$': {name}")
|
|
76
|
+
name = name.upper()
|
|
55
77
|
self.special_variables[name] = value
|
|
56
|
-
match name
|
|
78
|
+
match name:
|
|
57
79
|
case "$$CLP_STP_INTERVAL":
|
|
58
80
|
set_line_delay(value)
|
|
59
81
|
self.special_variables["$$STEP_INTERVAL"] = value
|
|
@@ -82,7 +104,8 @@ class CstolVariables:
|
|
|
82
104
|
"""
|
|
83
105
|
if not name.startswith('$$'):
|
|
84
106
|
raise ValueError(f"Special variable names must start with '$$': {name}")
|
|
85
|
-
|
|
107
|
+
name = name.upper()
|
|
108
|
+
match name:
|
|
86
109
|
case "$$CURRENT_TIME":
|
|
87
110
|
return datetime.datetime.now(datetime.timezone.utc).timestamp()
|
|
88
111
|
case "$$SC_TIME":
|
|
@@ -240,7 +263,19 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
240
263
|
i += 3 # Skip the next 2 tokens since we combined them
|
|
241
264
|
|
|
242
265
|
else:
|
|
243
|
-
|
|
266
|
+
# Recombine multi-part operator tokens
|
|
267
|
+
token = tokens[i]
|
|
268
|
+
if token in self.KNOWN_TOKENS and i + 1 < len(tokens):
|
|
269
|
+
next_token = tokens[i + 1]
|
|
270
|
+
if ((token == '*' and next_token == '*') or
|
|
271
|
+
(token == '<' and next_token == '=') or
|
|
272
|
+
(token == '>' and next_token == '=') or
|
|
273
|
+
(token == '/' and next_token == '=')):
|
|
274
|
+
reconstructed_tokens.append(token + next_token)
|
|
275
|
+
i += 2 # Skip the next token
|
|
276
|
+
continue
|
|
277
|
+
|
|
278
|
+
reconstructed_tokens.append(token)
|
|
244
279
|
i += 1
|
|
245
280
|
|
|
246
281
|
return reconstructed_tokens
|
|
@@ -280,7 +315,7 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
280
315
|
# Handle local variables
|
|
281
316
|
if token.startswith('$'):
|
|
282
317
|
# Get the actual value of local variable
|
|
283
|
-
value = self.variables.
|
|
318
|
+
value = self.variables.get_local_variable(token)
|
|
284
319
|
if value is None:
|
|
285
320
|
raise ValueError(f"Unknown variable: {token}")
|
|
286
321
|
if isinstance(value, str):
|
|
@@ -312,19 +347,19 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
312
347
|
continue
|
|
313
348
|
|
|
314
349
|
# Handle radix notation integers
|
|
315
|
-
|
|
350
|
+
# Allow hex digits (A-F) for all bases so X#FF and H#DEADBEEF parse;
|
|
351
|
+
# int() with the proper base validates the digits for each radix.
|
|
352
|
+
matches = re.match(r'^([BODXHbodxh])#([0-9A-Fa-f]+)$', token)
|
|
316
353
|
if matches is not None:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
case 'O':
|
|
321
|
-
final_tokens.append(f'0o{token[2:]}')
|
|
322
|
-
case 'D':
|
|
323
|
-
final_tokens.append(f'{token[2:]}')
|
|
354
|
+
radix_char = matches.group(1).upper()
|
|
355
|
+
digits = matches.group(2)
|
|
356
|
+
match radix_char:
|
|
324
357
|
case 'H':
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
358
|
+
# Hex byte buffer (raw bytes rather than an integer)
|
|
359
|
+
final_tokens.append(str(int(digits, 16).to_bytes((len(digits) + 1) // 2, 'big')))
|
|
360
|
+
case _:
|
|
361
|
+
base = {'B': 2, 'O': 8, 'D': 10, 'X': 16}[radix_char]
|
|
362
|
+
final_tokens.append(str(int(digits, base)))
|
|
328
363
|
previous_number = True
|
|
329
364
|
continue
|
|
330
365
|
|
|
@@ -359,7 +394,7 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
359
394
|
token = final_tokens[i]
|
|
360
395
|
|
|
361
396
|
# Check for "RAW" pattern first: "RAW", "TARGET_NAME", "ITEM_NAME"
|
|
362
|
-
if (token == '"RAW"' and i + 2 < len(final_tokens) and
|
|
397
|
+
if (token.upper() == '"RAW"' and i + 2 < len(final_tokens) and
|
|
363
398
|
final_tokens[i + 1].startswith('"') and final_tokens[i + 1].endswith('"') and
|
|
364
399
|
final_tokens[i + 2].startswith('"') and final_tokens[i + 2].endswith('"')):
|
|
365
400
|
|
|
@@ -388,7 +423,7 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
388
423
|
return ' '.join(processed_tokens)
|
|
389
424
|
|
|
390
425
|
# Combined regex pattern to match both formats
|
|
391
|
-
TIMESTAMP_PATTERN = r'(?:(\d{4})?/(\d{1,3})?-)?(\d{
|
|
426
|
+
TIMESTAMP_PATTERN = r'(?:(\d{4})?/(\d{1,3})?-)?(\d{0,2}):(\d{0,2}):(\d{1,2}\.?\d*)'
|
|
392
427
|
|
|
393
428
|
# Will convert a CSTOL Clock Time or Delta Time into floating point seconds
|
|
394
429
|
def parse_timestamp(self, timestamp, now = None):
|
|
@@ -398,6 +433,10 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
398
433
|
matches = re.match(self.TIMESTAMP_PATTERN, timestamp)
|
|
399
434
|
if matches:
|
|
400
435
|
year, day_of_year, hour, minute, second = matches.groups()
|
|
436
|
+
if len(hour) == 0:
|
|
437
|
+
hour = 0
|
|
438
|
+
if len(minute) == 0:
|
|
439
|
+
minute = 0
|
|
401
440
|
result = {
|
|
402
441
|
'hour': int(hour),
|
|
403
442
|
'minute': int(minute),
|
|
@@ -537,9 +576,12 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
537
576
|
question = question[1:-1]
|
|
538
577
|
answer = ask_string(question)
|
|
539
578
|
if answer is not None:
|
|
540
|
-
if answer[0] == '"' and answer[-1] == '"':
|
|
579
|
+
if len(answer) >= 2 and answer[0] == '"' and answer[-1] == '"':
|
|
541
580
|
# Remove quotes and don't uppercase and don't eval
|
|
542
581
|
answer = answer[1:-1]
|
|
582
|
+
elif answer.strip() == '':
|
|
583
|
+
# Empty answer - store as-is without tokenizing/evaluating
|
|
584
|
+
pass
|
|
543
585
|
else:
|
|
544
586
|
# Tokenize answer
|
|
545
587
|
answer_tokens = self.cstol_tokenizer(answer)
|
|
@@ -550,11 +592,13 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
550
592
|
# Uppercase
|
|
551
593
|
if isinstance(answer, str):
|
|
552
594
|
answer = answer.upper()
|
|
553
|
-
self.variables.
|
|
595
|
+
self.variables.set_local_variable(variable, answer)
|
|
554
596
|
|
|
555
597
|
def handle_check(self, tokens, line_no):
|
|
556
598
|
expressions = self.extract_expressions(tokens[1:], ",")
|
|
557
599
|
for expr in expressions:
|
|
600
|
+
if len(expr) == 0:
|
|
601
|
+
raise ValueError(f"Empty expression in CHECK command at line {line_no}")
|
|
558
602
|
format = None
|
|
559
603
|
if expr[0][0] == '%':
|
|
560
604
|
# Format string
|
|
@@ -742,7 +786,7 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
742
786
|
raise ValueError(f"Expected '=' after variable name in DECLARE command at line {line_no}")
|
|
743
787
|
#default_value = self.token_to_value(tokens[4])
|
|
744
788
|
default_value = self.evaluate_tokens([tokens[4]])[0]
|
|
745
|
-
self.variables.
|
|
789
|
+
self.variables.set_local_variable(variable_name, default_value)
|
|
746
790
|
|
|
747
791
|
def handle_display(self, tokens, line_no):
|
|
748
792
|
screen_name = tokens[1]
|
|
@@ -752,9 +796,29 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
752
796
|
display_screen(*screen_name.split())
|
|
753
797
|
|
|
754
798
|
def handle_else(self, tokens, lines, line_no):
|
|
755
|
-
|
|
799
|
+
goto_endif = False
|
|
800
|
+
if len(tokens) > 1:
|
|
801
|
+
# ELSE IF is tricky - We can hit these after a successful IF, or an unsuccessful IF
|
|
802
|
+
# The if_stack keeps track if an earlier if was successful and its value will determine if we
|
|
803
|
+
# execute the ELSEIF or just goto the next ENDIF
|
|
804
|
+
current_if = False
|
|
805
|
+
if len(self.variables.if_stack) > 0:
|
|
806
|
+
current_if = self.variables.if_stack[-1]
|
|
807
|
+
if tokens[0].upper() == 'ELSEIF':
|
|
808
|
+
if current_if:
|
|
809
|
+
goto_endif = True
|
|
810
|
+
else:
|
|
811
|
+
return self.handle_if(tokens, lines, line_no)
|
|
812
|
+
elif (tokens[0].upper() == 'ELSE' and tokens[1].upper() == 'IF'):
|
|
813
|
+
if current_if:
|
|
814
|
+
goto_endif = True
|
|
815
|
+
else:
|
|
816
|
+
return self.handle_if(tokens[1:], lines, line_no)
|
|
817
|
+
|
|
818
|
+
if goto_endif or (len(tokens) == 1 and tokens[0].upper() == 'ELSE'):
|
|
756
819
|
# The only way we ever hit an ELSE is if we were in a successful block beforehand
|
|
757
820
|
# Therefore goto the ENDIF
|
|
821
|
+
self.variables.if_stack[-1] = True
|
|
758
822
|
depth = 1
|
|
759
823
|
for i in range(line_no, len(lines)):
|
|
760
824
|
next_line = lines[i].strip().upper()
|
|
@@ -766,18 +830,16 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
766
830
|
return i + 1
|
|
767
831
|
raise ValueError(f"No matching ENDIF for ELSE command at line {line_no}")
|
|
768
832
|
|
|
769
|
-
|
|
770
|
-
if tokens[0] == 'ELSEIF':
|
|
771
|
-
return self.handle_if(tokens, lines, line_no)
|
|
772
|
-
elif (tokens[0] == 'ELSE' and tokens[1] == 'IF'):
|
|
773
|
-
return self.handle_if(tokens[1:], lines, line_no)
|
|
833
|
+
raise ValueError(f"handle_else called with unexpected tokens at line {line_no}")
|
|
774
834
|
|
|
775
835
|
def handle_end(self, tokens, line_no):
|
|
776
|
-
if len(tokens) == 1 and tokens[0] == 'END':
|
|
836
|
+
if len(tokens) == 1 and tokens[0].upper() == 'END':
|
|
777
837
|
raise ValueError(f"Unexpected END command at line {line_no}, expected ENDIF, ENDLOOP, ENDMACRO, or ENDPROC")
|
|
778
|
-
elif (len(tokens) == 1 and tokens[0] == 'ENDIF') or (tokens[0] == 'END' and tokens[1] == 'IF'):
|
|
838
|
+
elif (len(tokens) == 1 and tokens[0].upper() == 'ENDIF') or (tokens[0].upper() == 'END' and tokens[1].upper() == 'IF'):
|
|
839
|
+
# END IF pops the IF stack
|
|
840
|
+
self.variables.if_stack.pop()
|
|
779
841
|
pass
|
|
780
|
-
elif (len(tokens) == 1 and tokens[0] == 'ENDLOOP') or (tokens[0] == 'END' and tokens[1] == 'LOOP'):
|
|
842
|
+
elif (len(tokens) == 1 and tokens[0].upper() == 'ENDLOOP') or (tokens[0].upper() == 'END' and tokens[1].upper() == 'LOOP'):
|
|
781
843
|
if len(self.variables.loop_stack) > 0:
|
|
782
844
|
loop_info = self.variables.loop_stack[-1]
|
|
783
845
|
loop_info[2] += 1
|
|
@@ -798,10 +860,14 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
798
860
|
# Find the matching ENDLOOP
|
|
799
861
|
depth = 1
|
|
800
862
|
for i in range(line_no, len(lines)):
|
|
801
|
-
|
|
802
|
-
|
|
863
|
+
# Match on whole words so labels like "LOOPBACK:" are not mistaken
|
|
864
|
+
# for a nested LOOP keyword
|
|
865
|
+
words = lines[i].strip().upper().split()
|
|
866
|
+
if not words:
|
|
867
|
+
continue
|
|
868
|
+
if words[0] == 'LOOP':
|
|
803
869
|
depth += 1
|
|
804
|
-
elif
|
|
870
|
+
elif words[0] == 'ENDLOOP' or (words[0] == 'END' and len(words) > 1 and words[1] == 'LOOP'):
|
|
805
871
|
depth -= 1
|
|
806
872
|
if depth == 0:
|
|
807
873
|
if len(self.variables.loop_stack) > 0:
|
|
@@ -810,17 +876,17 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
810
876
|
raise ValueError(f"No matching ENDLOOP found for ESCAPE command at line {line_no}")
|
|
811
877
|
|
|
812
878
|
def handle_go(self, tokens, lines, line_no):
|
|
813
|
-
if tokens[0] == 'GOTO' or (len(tokens) > 1 and tokens[0] == 'GO' and tokens[1] == 'TO'):
|
|
814
|
-
if (tokens[0] == 'GOTO' and len(tokens) < 2) or (tokens[0] == 'GO' and
|
|
879
|
+
if tokens[0].upper() == 'GOTO' or (len(tokens) > 1 and tokens[0].upper() == 'GO' and tokens[1].upper() == 'TO'):
|
|
880
|
+
if (tokens[0].upper() == 'GOTO' and len(tokens) < 2) or (tokens[0].upper() == 'GO' and len(tokens) < 3):
|
|
815
881
|
raise ValueError(f"Invalid GOTO command format at line {line_no}")
|
|
816
882
|
label = None
|
|
817
|
-
if tokens[0] == 'GOTO':
|
|
818
|
-
label = tokens[1] + ':'
|
|
883
|
+
if tokens[0].upper() == 'GOTO':
|
|
884
|
+
label = (tokens[1] + ':').upper()
|
|
819
885
|
else:
|
|
820
|
-
label = tokens[2] + ':'
|
|
886
|
+
label = (tokens[2] + ':').upper()
|
|
821
887
|
# Find the label in the lines
|
|
822
888
|
for i in range(1, len(lines)):
|
|
823
|
-
next_line = lines[i - 1].strip()
|
|
889
|
+
next_line = lines[i - 1].strip().upper()
|
|
824
890
|
if next_line.startswith(label):
|
|
825
891
|
return i
|
|
826
892
|
raise ValueError(f"Label '{label}' not found in GOTO command at line {line_no}")
|
|
@@ -835,6 +901,8 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
835
901
|
raise ValueError(f"Error evaluating expression '{expression_tokens}' in IF command at line {line_no}: {e}")
|
|
836
902
|
|
|
837
903
|
if result:
|
|
904
|
+
# Mark if as handled
|
|
905
|
+
self.variables.if_stack[-1] = True
|
|
838
906
|
return line_no + 1 # Continue to the next line if the condition is true
|
|
839
907
|
# If the condition is false, skip to the next ENDIF or ELSE
|
|
840
908
|
else:
|
|
@@ -897,7 +965,7 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
897
965
|
self.variables.set_special_variable(variable_name, result)
|
|
898
966
|
else:
|
|
899
967
|
# Local variable
|
|
900
|
-
self.variables.
|
|
968
|
+
self.variables.set_local_variable(variable_name, result)
|
|
901
969
|
|
|
902
970
|
def handle_load(self, tokens, line_no):
|
|
903
971
|
# LOAD external-element-name AT location FROM file-name
|
|
@@ -923,14 +991,11 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
923
991
|
if len(tokens) == 1:
|
|
924
992
|
# Infinite loop
|
|
925
993
|
self.variables.loop_stack.append([line_no + 1, None, 1])
|
|
926
|
-
return line_no + 1 # Continue to the next line
|
|
927
|
-
elif len(tokens) == 2:
|
|
928
|
-
# Counted loop
|
|
929
|
-
count = int(tokens[1])
|
|
930
|
-
self.variables.loop_stack.append([line_no + 1, count, 1])
|
|
931
|
-
return line_no + 1 # Continue to the next line
|
|
932
994
|
else:
|
|
933
|
-
|
|
995
|
+
# Counted loop - the count may be a literal, variable, or expression
|
|
996
|
+
count = int(self.evaluate_expression(tokens[1:]))
|
|
997
|
+
self.variables.loop_stack.append([line_no + 1, count, 1])
|
|
998
|
+
return line_no + 1 # Continue to the next line
|
|
934
999
|
|
|
935
1000
|
def handle_proc(self, tokens, line_no):
|
|
936
1001
|
# tokens[1] is proc name
|
|
@@ -941,7 +1006,7 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
941
1006
|
if token == ',':
|
|
942
1007
|
continue
|
|
943
1008
|
elif token.startswith('$'):
|
|
944
|
-
self.variables.
|
|
1009
|
+
self.variables.set_local_variable(token, os.getenv(f"CSTOL_ARG_{index}"))
|
|
945
1010
|
index += 1
|
|
946
1011
|
else:
|
|
947
1012
|
raise ValueError(f"Invalid variable '{token}' in PROC command at line {line_no}")
|
|
@@ -949,7 +1014,7 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
949
1014
|
def handle_return(self, tokens, lines, line_no):
|
|
950
1015
|
if len(tokens) > 1:
|
|
951
1016
|
if tokens[1].upper() == 'ALL':
|
|
952
|
-
raise
|
|
1017
|
+
raise StopScriptError
|
|
953
1018
|
return (len(lines) + 1)
|
|
954
1019
|
|
|
955
1020
|
def handle_run(self, tokens, line_no):
|
|
@@ -1052,6 +1117,8 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
1052
1117
|
expressions = self.extract_expressions(tokens[1:], ",")
|
|
1053
1118
|
results = []
|
|
1054
1119
|
for expr in expressions:
|
|
1120
|
+
if len(expr) == 0:
|
|
1121
|
+
raise ValueError(f"Empty expression in WRITE command at line {line_no}")
|
|
1055
1122
|
result = ''
|
|
1056
1123
|
if expr[0][0] == '%':
|
|
1057
1124
|
# Format string
|
|
@@ -1166,6 +1233,8 @@ class CstolScriptEngine(ScriptEngine):
|
|
|
1166
1233
|
case "GO" | "GOTO":
|
|
1167
1234
|
return self.handle_go(tokens, lines, line_no)
|
|
1168
1235
|
case "IF":
|
|
1236
|
+
# Regular IF starts an if stack
|
|
1237
|
+
self.variables.if_stack.append(False)
|
|
1169
1238
|
return self.handle_if(tokens, lines, line_no)
|
|
1170
1239
|
case "LET":
|
|
1171
1240
|
self.handle_let(tokens, line_no)
|
|
Binary file
|
metadata
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openc3-cosmos-script-engine-cstol
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- OpenC3, Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-06-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: " This plugin provides a script engine to support CSTOL in Script Runner\n"
|
|
14
14
|
email:
|
|
15
|
-
-
|
|
15
|
+
- plugins@openc3.com
|
|
16
16
|
executables: []
|
|
17
17
|
extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
|
@@ -22,12 +22,19 @@ files:
|
|
|
22
22
|
- Rakefile
|
|
23
23
|
- lib/cstol_script_engine.py
|
|
24
24
|
- plugin.txt
|
|
25
|
+
- public/store_img.png
|
|
25
26
|
- targets/CSTOL_TEST/procedures/collect.prc
|
|
26
27
|
- targets/CSTOL_TEST/procedures/test.prc
|
|
27
28
|
homepage: https://github.com/OpenC3/openc3-cosmos-script-engine-cstol
|
|
28
29
|
licenses:
|
|
29
30
|
- Nonstandard
|
|
30
|
-
metadata:
|
|
31
|
+
metadata:
|
|
32
|
+
source_code_uri: https://github.com/OpenC3/openc3-cosmos-script-engine-cstol
|
|
33
|
+
openc3_store_title: CSTOL Script Engine
|
|
34
|
+
openc3_store_keywords: script, cstol
|
|
35
|
+
openc3_store_image: public/store_img.png
|
|
36
|
+
openc3_store_access_type: public
|
|
37
|
+
openc3_cosmos_minimum_version: 7.0.0
|
|
31
38
|
post_install_message:
|
|
32
39
|
rdoc_options: []
|
|
33
40
|
require_paths:
|
|
@@ -46,5 +53,5 @@ requirements: []
|
|
|
46
53
|
rubygems_version: 3.5.22
|
|
47
54
|
signing_key:
|
|
48
55
|
specification_version: 4
|
|
49
|
-
summary: OpenC3 Script Engine
|
|
56
|
+
summary: OpenC3 CSTOL Script Engine
|
|
50
57
|
test_files: []
|