openc3-cosmos-demo 6.0.2 → 6.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/targets/INST/cmd_tlm/inst_cmds.txt +2 -0
- data/targets/INST/cmd_tlm/inst_tlm.txt +10 -0
- data/targets/INST/lib/inst_cmd_validator.rb +1 -0
- data/targets/INST/lib/sim_inst.rb +3 -0
- data/targets/INST/procedures/calendar.rb +52 -27
- data/targets/INST/procedures/checks.rb +1 -1
- data/targets/INST/procedures/disconnect.rb +1 -1
- data/targets/INST/procedures/scripting.rb +88 -0
- data/targets/INST/screens/graphs.txt +28 -23
- data/targets/INST2/cmd_tlm/inst_cmds.txt +5 -1
- data/targets/INST2/cmd_tlm/inst_tlm.txt +10 -1
- data/targets/INST2/lib/sim_inst.py +3 -0
- data/targets/INST2/procedures/calendar.py +53 -38
- data/targets/INST2/procedures/disconnect.py +1 -1
- data/targets/INST2/procedures/scripting.py +84 -0
- data/targets/INST2/screens/graphs.txt +28 -23
- data/tools/widgets/BigWidget/BigWidget.umd.min.js +98 -98
- data/tools/widgets/BigWidget/BigWidget.umd.min.js.map +1 -1
- data/tools/widgets/DataviewerquaternionWidget/DataviewerquaternionWidget.umd.min.js +114 -114
- data/tools/widgets/DataviewerquaternionWidget/DataviewerquaternionWidget.umd.min.js.map +1 -1
- data/tools/widgets/DataviewertimeWidget/DataviewertimeWidget.umd.min.js +98 -98
- data/tools/widgets/DataviewertimeWidget/DataviewertimeWidget.umd.min.js.map +1 -1
- data/tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js +98 -98
- data/tools/widgets/HelloworldWidget/HelloworldWidget.umd.min.js.map +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c888a30f0d6951c4b7c2c10f8868e8c80569e09eac181b6998777c79d824b4a0
|
4
|
+
data.tar.gz: 9d7ec85c58a58937720cb368059bca004544cd1d8f6227c65c7fba83dc75d96a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e818d703ee7703d87cd5796da6efb4aa83b1f17a934ebd0aa25a3dc89af83640464a2193d40c45d054d82543e899291bfb3732498362dc5fed8c95f7b2f40fe3
|
7
|
+
data.tar.gz: 466106a6e5effdf51249e8ad0cd7780b66350fd94450498020331b591a8f1fc4209d9d0878b8f4045b4bfe0385238dc488065985e8ab30ea0d5e726af159b58b
|
@@ -97,6 +97,8 @@ COMMAND <%= target_name %> TIME_OFFSET BIG_ENDIAN "Subtract the packet time by t
|
|
97
97
|
VALIDATOR inst_cmd_validator.rb
|
98
98
|
<%= render "_ccsds_cmd.txt", locals: {id: 12} %>
|
99
99
|
APPEND_PARAMETER SECONDS 32 UINT MIN MAX 0 "Seconds to subtract from packet time"
|
100
|
+
APPEND_PARAMETER IP_ADDRESS 32 UINT MIN MAX "127.0.0.1" "IP address"
|
101
|
+
WRITE_CONVERSION ip_write_conversion.rb
|
100
102
|
|
101
103
|
COMMAND <%= target_name %> HIDDEN BIG_ENDIAN "Hidden command to bump the hidden packet"
|
102
104
|
VALIDATOR inst_cmd_validator.rb
|
@@ -73,6 +73,14 @@ TELEMETRY <%= target_name %> HEALTH_STATUS BIG_ENDIAN "Health and status from th
|
|
73
73
|
GENERIC_READ_CONVERSION_START FLOAT 32
|
74
74
|
packet.read('TEMP1') * 1_000_000
|
75
75
|
GENERIC_READ_CONVERSION_END
|
76
|
+
# Enable to test the ARRAYPLOT widget with array of array data [[x1,x2,...],[y1,y2,...]]
|
77
|
+
# ITEM POINTS 0 0 DERIVED
|
78
|
+
# GENERIC_READ_CONVERSION_START UINT 800
|
79
|
+
# return [
|
80
|
+
# Array.new(800) { |i| i * 0.1 },
|
81
|
+
# (0...800).map { |i| Math.sin(2 * Math::PI * i / 800) }
|
82
|
+
# ]
|
83
|
+
# GENERIC_READ_CONVERSION_END
|
76
84
|
PROCESSOR TEMP1STAT statistics_processor.rb TEMP1 100
|
77
85
|
PROCESSOR TEMP1WATER watermark_processor.rb TEMP1
|
78
86
|
|
@@ -127,6 +135,7 @@ TELEMETRY <%= target_name %> PARAMS BIG_ENDIAN "Params set by SETPARAMS command"
|
|
127
135
|
STATE GOOD 0 GREEN
|
128
136
|
STATE BAD 1 RED
|
129
137
|
<% end %>
|
138
|
+
APPEND_ITEM IP_ADDRESS 32 UINT "Encoded IP Address"
|
130
139
|
APPEND_ITEM P_2.2,2 32 UINT "Test weird characters"
|
131
140
|
APPEND_ITEM P-3+3=3 32 UINT "Test weird characters"
|
132
141
|
APPEND_ITEM P4!@#$%^&*? 32 UINT "Test weird characters"
|
@@ -160,6 +169,7 @@ TELEMETRY <%= target_name %> MECH BIG_ENDIAN "Mechanism status ©®"
|
|
160
169
|
UNITS DEGREES DEG
|
161
170
|
APPEND_ITEM CURRENT 32 FLOAT "Device current"
|
162
171
|
UNITS micro-Ampères µA
|
172
|
+
APPEND_ITEM STRING 0 STRING "String"
|
163
173
|
ITEM PACKET_TIME 0 0 DERIVED "Ruby time based on TIMESEC and TIMEUS"
|
164
174
|
READ_CONVERSION unix_time_conversion.rb TIMESEC TIMEUS
|
165
175
|
|
@@ -22,6 +22,7 @@ class InstCmdValidator < OpenC3::CommandValidator
|
|
22
22
|
def pre_check(command)
|
23
23
|
# Record the current value of CMD_ACPT_CNT for comparison in post_check
|
24
24
|
@cmd_acpt_cnt = tlm("<%= target_name %> HEALTH_STATUS CMD_ACPT_CNT")
|
25
|
+
@cmd_acpt_cnt ||= 0 # If the telemetry value is nil, set it to 0
|
25
26
|
return [true, nil]
|
26
27
|
end
|
27
28
|
|
@@ -152,6 +152,7 @@ module OpenC3
|
|
152
152
|
@last_temp2 = 0
|
153
153
|
@quiet = false
|
154
154
|
@time_offset = 0
|
155
|
+
@ip_address = 0
|
155
156
|
end
|
156
157
|
|
157
158
|
def set_rates
|
@@ -238,6 +239,7 @@ module OpenC3
|
|
238
239
|
when 'TIME_OFFSET'
|
239
240
|
hs_packet.cmd_acpt_cnt += 1
|
240
241
|
@time_offset = packet.read('seconds')
|
242
|
+
@ip_address = packet.read('ip_address')
|
241
243
|
when 'HIDDEN'
|
242
244
|
# Deliberately do not increment cmd_acpt_cnt
|
243
245
|
@tlm_packets['HIDDEN'].count = packet.read('count')
|
@@ -378,6 +380,7 @@ module OpenC3
|
|
378
380
|
packet.timesec = time.tv_sec - @time_offset
|
379
381
|
packet.timeus = time.tv_usec
|
380
382
|
packet.ccsdsseqcnt += 1
|
383
|
+
packet.ip_address = @ip_address
|
381
384
|
|
382
385
|
when 'IMAGE'
|
383
386
|
packet.timesec = time.tv_sec - @time_offset
|
@@ -1,43 +1,68 @@
|
|
1
|
-
tl = create_timeline("
|
2
|
-
puts tl #=> {"name"=>"
|
1
|
+
tl = create_timeline("RubyTL")
|
2
|
+
puts tl #=> {"name"=>"RubyTL", "color"=>"#cdce42", "execute"=>true, "shard"=>0, "scope"=>"DEFAULT", "updated_at"=>1737128664493258134}
|
3
3
|
tls = list_timelines()
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
check_expression("#{list_timelines().length} == 0")
|
4
|
+
names = tls.map { |tl| tl['name'] }
|
5
|
+
check_expression("#{names.include?('RubyTL')} == true")
|
6
|
+
puts tls[0] #=> {"name"=>"RubyTL", "color"=>"#cdce42", "execute"=>true, "shard"=>0, "scope"=>"DEFAULT", "updated_at"=>1737128664493258134}
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
puts get_timeline("Mine") #=> {"name"=>"Mine", "color"=>"#4287f5", "scope"=>"DEFAULT", "updated_at"=>1698763720728596964}
|
8
|
+
set_timeline_color("RubyTL", "#4287f5")
|
9
|
+
puts get_timeline("RubyTL") #=> {"name"=>"RubyTL", "color"=>"#4287f5", "execute"=>true, "shard"=>0, "scope"=>"DEFAULT", "updated_at"=>1737128689586673173}
|
12
10
|
|
13
11
|
now = Time.now()
|
14
12
|
start = now + 3600
|
15
|
-
stop = start + 3600
|
16
|
-
|
13
|
+
stop = start + 3600
|
14
|
+
act1 = create_timeline_activity("RubyTL", kind: "RESERVE", start: start, stop: stop)
|
15
|
+
puts act1 #=>
|
16
|
+
# { "name"=>"RubyTL", "updated_at"=>1737128705034982375, "start"=>1737132303, "stop"=>1737135903,
|
17
|
+
# "kind"=>"reserve", "data"=>{"username"=>"operator"},
|
18
|
+
# "scope"=>"DEFAULT", "fulfillment"=>false, "uuid"=>"5f373846-eb6c-43cd-97bd-cca19a8ffb04",
|
19
|
+
# "events"=>[{"time"=>1737128705, "event"=>"created"}], "recurring"=>{}}
|
20
|
+
act2 = create_timeline_activity("RubyTL", kind: "COMMAND", start: start, stop: stop,
|
21
|
+
data: {command: "INST COLLECT with TYPE NORMAL, DURATION 5, TEMP 10"})
|
22
|
+
puts act2 #=>
|
23
|
+
# { "name"=>"RubyTL", "updated_at"=>1737128761316084471, "start"=>1737132303, "stop"=>1737135903,
|
24
|
+
# "kind"=>"command", "data"=>{"command"=>"INST COLLECT with TYPE NORMAL, DURATION 5, TEMP 10", "username"=>"operator"},
|
25
|
+
# "scope"=>"DEFAULT", "fulfillment"=>false, "uuid"=>"cdb661b4-a65b-44e7-95e2-5e1dba80c782",
|
26
|
+
# "events"=>[{"time"=>1737128761, "event"=>"created"}], "recurring"=>{}}
|
27
|
+
start = now + 7200
|
28
|
+
stop = start + 3600
|
29
|
+
act3 = create_timeline_activity("RubyTL", kind: "SCRIPT", start: start, stop: stop,
|
30
|
+
data: {environment: [{key: "USER", value: "JASON"}], script: "INST/procedures/checks.rb"})
|
31
|
+
puts act3 #=>
|
32
|
+
# { "name"=>"RubyTL", "updated_at"=>1737128791047885970, "start"=>1737135903, "stop"=>1737139503,
|
33
|
+
# "kind"=>"script", "data"=>{"environment"=>[{"key"=>"USER", "value"=>"JASON"}], "script"=>"INST/procedures/checks.rb", "username"=>"operator"},
|
34
|
+
# "scope"=>"DEFAULT", "fulfillment"=>false, "uuid"=>"70426e3d-6313-4897-b159-6e5cd94ace1d",
|
35
|
+
# "events"=>[{"time"=>1737128791, "event"=>"created"}], "recurring"=>{}}
|
36
|
+
|
37
|
+
act = get_timeline_activity("RubyTL", act2['start'], act2['uuid'])
|
17
38
|
puts act #=>
|
18
|
-
# { "name"=>"
|
19
|
-
# "
|
20
|
-
# "
|
39
|
+
# { "name"=>"RubyTL", "updated_at"=>1737128761316084471, "start"=>1737132303, "stop"=>1737135903,
|
40
|
+
# "kind"=>"command", "data"=>{"command"=>"INST COLLECT with TYPE NORMAL, DURATION 5, TEMP 10", "username"=>"operator"},
|
41
|
+
# "scope"=>"DEFAULT", "fulfillment"=>false, "uuid"=>"cdb661b4-a65b-44e7-95e2-5e1dba80c782",
|
42
|
+
# "events"=>[{"time"=>1737128761, "event"=>"created"}], "recurring"=>{}}
|
43
|
+
|
21
44
|
# Get activities in the past ... should be none
|
22
|
-
tlas = get_timeline_activities("
|
45
|
+
tlas = get_timeline_activities("RubyTL", start: Time.now() - 3600, stop: Time.now())
|
23
46
|
check_expression("#{tlas.length} == 0")
|
24
|
-
# Get all activities
|
25
|
-
tlas = get_timeline_activities("
|
26
|
-
check_expression("#{tlas.length} ==
|
47
|
+
# Get all activities at plus and minus 1 week
|
48
|
+
tlas = get_timeline_activities("RubyTL")
|
49
|
+
check_expression("#{tlas.length} == 3")
|
27
50
|
|
28
51
|
# Create and delete a new activity
|
29
52
|
start = start + 7200
|
30
53
|
stop = start + 300
|
31
|
-
act = create_timeline_activity("
|
32
|
-
tlas = get_timeline_activities("
|
33
|
-
check_expression("#{tlas.length} ==
|
34
|
-
delete_timeline_activity("
|
35
|
-
tlas = get_timeline_activities("
|
36
|
-
check_expression("#{tlas.length} ==
|
54
|
+
act = create_timeline_activity("RubyTL", kind: "reserve", start: start, stop: stop)
|
55
|
+
tlas = get_timeline_activities("RubyTL")
|
56
|
+
check_expression("#{tlas.length} == 4")
|
57
|
+
delete_timeline_activity("RubyTL", act['start'], act['uuid'])
|
58
|
+
tlas = get_timeline_activities("RubyTL")
|
59
|
+
check_expression("#{tlas.length} == 3")
|
37
60
|
|
38
61
|
# delete fails since the timeline has activities
|
39
|
-
delete_timeline("
|
62
|
+
delete_timeline("RubyTL") #=> RuntimeError : Failed to delete timeline due to timeline contains activities, must force remove
|
40
63
|
# Force delete since the timeline has activities
|
41
|
-
delete_timeline("
|
64
|
+
delete_timeline("RubyTL", force: true)
|
65
|
+
# Verify the timeline no longer exists
|
42
66
|
tls = list_timelines()
|
43
|
-
|
67
|
+
names = tls.map { |tl| tl['name'] }
|
68
|
+
check_expression("#{names.include?('RubyTL')} == false")
|
@@ -17,5 +17,5 @@ wait_expression("true == false", 5)
|
|
17
17
|
wait_packet("<%= target_name %>","ADCS", 2, 5)
|
18
18
|
wait_check("<%= target_name %> ADCS BIASX == 100", 5)
|
19
19
|
wait_check_tolerance("<%= target_name %> ADCS BIASX", 5, 0.5, 5)
|
20
|
-
wait_check_expression("
|
20
|
+
wait_check_expression("tlm('<%= target_name %> HEALTH_STATUS TEMP1') < 101", 5, 0.25)
|
21
21
|
wait_check_packet("<%= target_name %>","ADCS", 2, 5)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Helper method to check for a script to change state
|
2
|
+
def wait_for_action(id, state)
|
3
|
+
i = 0
|
4
|
+
while i < 100
|
5
|
+
script = running_script_get(id)
|
6
|
+
if script['state'] == state
|
7
|
+
check_expression("'#{script['state']}' == '#{state}'")
|
8
|
+
break
|
9
|
+
end
|
10
|
+
wait 0.1
|
11
|
+
end
|
12
|
+
check_expression("'#{script['state']}' == '#{state}'")
|
13
|
+
end
|
14
|
+
|
15
|
+
SCRIPT_NAME = "INST/procedures/new_script.rb"
|
16
|
+
|
17
|
+
# Ensure it's not already there
|
18
|
+
step_mode()
|
19
|
+
script_delete(SCRIPT_NAME)
|
20
|
+
scripts = script_list()
|
21
|
+
check_expression("#{scripts.length} > 100")
|
22
|
+
run_mode()
|
23
|
+
|
24
|
+
contents = "puts('bad"
|
25
|
+
script_create(SCRIPT_NAME, contents)
|
26
|
+
body = script_body(SCRIPT_NAME)
|
27
|
+
result = script_syntax_check(body)
|
28
|
+
check_expression("#{result['success']} == false")
|
29
|
+
|
30
|
+
# Create a valid script that doesn't complete
|
31
|
+
contents = "set_line_delay(1)\nputs 'Hello from Ruby'\nputs('.')\nputs('.')\nwhile true\nputs Time.now\nwait 0.5\nwait 0.5\nend"
|
32
|
+
script_create(SCRIPT_NAME, contents)
|
33
|
+
scripts = script_list()
|
34
|
+
check_expression("#{scripts.include?(SCRIPT_NAME)} == true")
|
35
|
+
|
36
|
+
script = script_instrumented(contents)
|
37
|
+
check_expression("#{script.include?('RunningScript')} == true")
|
38
|
+
|
39
|
+
id = script_run(SCRIPT_NAME)
|
40
|
+
check_expression("#{id.to_i} > 0")
|
41
|
+
wait_for_action(id, 'running')
|
42
|
+
|
43
|
+
list = running_script_list()
|
44
|
+
started = list.select {|script| script["id"] == id}[0]
|
45
|
+
check_expression("'#{started['name']}' == SCRIPT_NAME")
|
46
|
+
script = running_script_get(id)
|
47
|
+
check_expression("'#{script['name']}' == SCRIPT_NAME")
|
48
|
+
|
49
|
+
running_script_pause(id)
|
50
|
+
wait_for_action(id, 'paused')
|
51
|
+
running_script_step(id)
|
52
|
+
wait_for_action(id, 'paused')
|
53
|
+
running_script_retry(id)
|
54
|
+
wait_for_action(id, 'paused')
|
55
|
+
running_script_go(id)
|
56
|
+
wait_for_action(id, 'running')
|
57
|
+
running_script_stop(id)
|
58
|
+
wait 1
|
59
|
+
|
60
|
+
list = running_script_list()
|
61
|
+
script = list.select {|script| script["id"] == id}[0]
|
62
|
+
# Script is stopped so it should NOT be in the running list
|
63
|
+
check_expression("#{script.nil?} == true")
|
64
|
+
|
65
|
+
list = completed_script_list()
|
66
|
+
script = list.select {|script| script["id"] == id}[0]
|
67
|
+
# Script is completed so it should be in the completed list
|
68
|
+
check_expression("#{script.nil?} == false")
|
69
|
+
|
70
|
+
id = script_run(SCRIPT_NAME)
|
71
|
+
wait_for_action(id, 'running')
|
72
|
+
running_script_delete(id) # Stop and completely remove the script
|
73
|
+
wait 1
|
74
|
+
|
75
|
+
list = running_script_list()
|
76
|
+
script = list.select {|script| script["id"] == id}[0]
|
77
|
+
# Script is deleted, so it should NOT be in the running list
|
78
|
+
check_expression("#{script.nil?} == true")
|
79
|
+
list = completed_script_list()
|
80
|
+
# Script is deleted so it should be in the completed list
|
81
|
+
script = list.select {|script| script["id"] == id}[0]
|
82
|
+
check_expression("#{script.nil?} == false")
|
83
|
+
|
84
|
+
script_lock(SCRIPT_NAME)
|
85
|
+
script_unlock(SCRIPT_NAME)
|
86
|
+
script_delete(SCRIPT_NAME)
|
87
|
+
scripts = script_list()
|
88
|
+
check_expression("#{scripts.include?(SCRIPT_NAME)} == false")
|
@@ -1,27 +1,32 @@
|
|
1
1
|
SCREEN AUTO AUTO 1.0
|
2
2
|
|
3
|
-
|
4
|
-
TITLE "<%= target_name %> Instrument Graphs"
|
3
|
+
TITLE "<%= target_name %> Instrument Graphs"
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
END
|
5
|
+
MATRIXBYCOLUMNS 2
|
6
|
+
SPARKLINE <%= target_name %> HEALTH_STATUS TEMP1
|
7
|
+
SETTING SIZE 400 50
|
8
|
+
SETTING HISTORY 30s
|
9
|
+
SPARKLINE <%= target_name %> HEALTH_STATUS TEMP2
|
10
|
+
SETTING SIZE 400 50
|
11
|
+
SETTING HISTORY 30s
|
12
|
+
LABELSPARKLINE <%= target_name %> HEALTH_STATUS TEMP3
|
13
|
+
LABELSPARKLINE <%= target_name %> HEALTH_STATUS TEMP4
|
14
|
+
LINEGRAPH <%= target_name %> HEALTH_STATUS TEMP1
|
15
|
+
SETTING ITEM <%= target_name %> ADCS Q1
|
16
|
+
LINEGRAPH <%= target_name %> HEALTH_STATUS TEMP2 RAW
|
17
|
+
SETTING SECONDSGRAPHED 60
|
18
|
+
SETTING POINTSSAVED 600
|
19
|
+
SETTING POINTSGRAPHED 60
|
20
|
+
LINEGRAPH <%= target_name %> HEALTH_STATUS TEMP3 CONVERTED REDUCED_MINUTE MIN
|
21
|
+
SETTING SIZE 600 500 # width height
|
22
|
+
SETTING HISTORY 1h
|
23
|
+
LINEGRAPH <%= target_name %> HEALTH_STATUS TEMP4
|
24
|
+
SETTING HISTORY 30m
|
27
25
|
END
|
26
|
+
|
27
|
+
ARRAYPLOT
|
28
|
+
SETTING TITLE "Array Data"
|
29
|
+
SETTING ITEM INST HEALTH_STATUS ARY
|
30
|
+
SETTING ITEM INST HEALTH_STATUS ARY2
|
31
|
+
SETTING SIZE 600 400
|
32
|
+
SETTING X_AXIS 10 10
|
@@ -29,9 +29,11 @@ COMMAND <%= target_name %> SETPARAMS BIG_ENDIAN "Sets numbered parameters"
|
|
29
29
|
<%= render "_ccsds_cmd.txt", locals: {id: 4} %>
|
30
30
|
# ERB syntax:
|
31
31
|
<% (1..5).each do |i| %>
|
32
|
-
|
32
|
+
# The packet is BIG_ENDIAN (CCSDS) but these fields are LITTLE_ENDIAN
|
33
|
+
APPEND_PARAMETER VALUE<%= i %> 16 UINT 0 5 1 "Value <%= i %> setting" LITTLE_ENDIAN
|
33
34
|
RELATED_ITEM <%= target_name %> PARAMS VALUE<%= i %>
|
34
35
|
<% end %>
|
36
|
+
SCREEN <%= target_name %> PARAMS
|
35
37
|
|
36
38
|
SELECT_PARAMETER VALUE5
|
37
39
|
POLY_WRITE_CONVERSION 0 2
|
@@ -95,6 +97,8 @@ COMMAND <%= target_name %> TIME_OFFSET BIG_ENDIAN "Subtract the packet time by t
|
|
95
97
|
VALIDATOR inst2_cmd_validator.py
|
96
98
|
<%= render "_ccsds_cmd.txt", locals: {id: 12} %>
|
97
99
|
APPEND_PARAMETER SECONDS 32 UINT MIN MAX 0 "Seconds to subtract from packet time"
|
100
|
+
APPEND_PARAMETER IP_ADDRESS 32 UINT MIN MAX "127.0.0.1" "IP address"
|
101
|
+
WRITE_CONVERSION openc3/conversions/ip_write_conversion.py
|
98
102
|
|
99
103
|
COMMAND <%= target_name %> HIDDEN BIG_ENDIAN "Hidden command to bump the hidden packet"
|
100
104
|
VALIDATOR inst2_cmd_validator.py
|
@@ -65,6 +65,14 @@ TELEMETRY <%= target_name %> HEALTH_STATUS BIG_ENDIAN "Health and status from th
|
|
65
65
|
READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1STAT MEAN
|
66
66
|
ITEM TEMP1STDDEV 0 0 DERIVED "Stddev of most recent 100 samples for TEMP1"
|
67
67
|
READ_CONVERSION openc3/conversions/processor_conversion.py TEMP1STAT STDDEV
|
68
|
+
ITEM TEMP1_MICRO 0 0 DERIVED
|
69
|
+
GENERIC_READ_CONVERSION_START FLOAT 32
|
70
|
+
packet.read('TEMP1') / 1_000_000
|
71
|
+
GENERIC_READ_CONVERSION_END
|
72
|
+
ITEM TEMP1_MEGA 0 0 DERIVED
|
73
|
+
GENERIC_READ_CONVERSION_START FLOAT 32
|
74
|
+
packet.read('TEMP1') * 1_000_000
|
75
|
+
GENERIC_READ_CONVERSION_END
|
68
76
|
PROCESSOR TEMP1STAT openc3/processors/statistics_processor.py TEMP1 100
|
69
77
|
PROCESSOR TEMP1WATER openc3/processors/watermark_processor.py TEMP1
|
70
78
|
|
@@ -119,6 +127,7 @@ TELEMETRY <%= target_name %> PARAMS BIG_ENDIAN "Params set by SETPARAMS command"
|
|
119
127
|
STATE GOOD 0 GREEN
|
120
128
|
STATE BAD 1 RED
|
121
129
|
<% end %>
|
130
|
+
APPEND_ITEM IP_ADDRESS 32 UINT "Encoded IP Address"
|
122
131
|
APPEND_ITEM P_2.2,2 32 UINT "Test weird characters"
|
123
132
|
APPEND_ITEM P-3+3=3 32 UINT "Test weird characters"
|
124
133
|
APPEND_ITEM P4!@#$%^&*? 32 UINT "Test weird characters"
|
@@ -137,7 +146,7 @@ TELEMETRY <%= target_name %> IMAGE BIG_ENDIAN "Packet with image data"
|
|
137
146
|
ITEM PACKET_TIME 0 0 DERIVED "Python time based on TIMESEC and TIMEUS"
|
138
147
|
READ_CONVERSION openc3/conversions/unix_time_conversion.py TIMESEC TIMEUS
|
139
148
|
|
140
|
-
TELEMETRY <%= target_name %> MECH BIG_ENDIAN "Mechanism status"
|
149
|
+
TELEMETRY <%= target_name %> MECH BIG_ENDIAN "Mechanism status ©®"
|
141
150
|
<%= render "_ccsds_tlm.txt", locals: {apid: 5} %>
|
142
151
|
APPEND_ITEM EXTRA 32 FLOAT "Extra item to be deleted"
|
143
152
|
APPEND_ITEM SLRPNL1 32 FLOAT "Solar panel 1 angle"
|
@@ -148,6 +148,7 @@ class SimInst(SimulatedTarget):
|
|
148
148
|
self.last_temp2 = 0
|
149
149
|
self.quiet = False
|
150
150
|
self.time_offset = 0
|
151
|
+
self.ip_address = 0
|
151
152
|
|
152
153
|
def set_rates(self):
|
153
154
|
self.set_rate("ADCS", 10)
|
@@ -213,6 +214,7 @@ class SimInst(SimulatedTarget):
|
|
213
214
|
case "TIME_OFFSET":
|
214
215
|
hs_packet.write("cmd_acpt_cnt", hs_packet.read("cmd_acpt_cnt") + 1)
|
215
216
|
self.time_offset = packet.read("seconds")
|
217
|
+
self.ip_address = packet.read("ip_address")
|
216
218
|
case "HIDDEN":
|
217
219
|
# Deliberately do not increment cmd_acpt_cnt
|
218
220
|
self.tlm_packets["HIDDEN"].count = packet.read("count")
|
@@ -382,6 +384,7 @@ class SimInst(SimulatedTarget):
|
|
382
384
|
packet.write("timesec", int(time - self.time_offset))
|
383
385
|
packet.write("timeus", int((time % 1) * 1000000))
|
384
386
|
packet.write("ccsdsseqcnt", packet.read("ccsdsseqcnt") + 1)
|
387
|
+
packet.write("ip_address", self.ip_address)
|
385
388
|
|
386
389
|
case "IMAGE":
|
387
390
|
packet.write("timesec", int(time - self.time_offset))
|
@@ -1,57 +1,72 @@
|
|
1
1
|
from datetime import datetime, timezone, timedelta
|
2
2
|
|
3
|
-
tl = create_timeline("
|
4
|
-
print(
|
5
|
-
tl
|
6
|
-
) # => {"name":"Mine", "color":"#ae2d1b", "scope":"DEFAULT", "updated_at":1698763720728596964}
|
3
|
+
tl = create_timeline("PythonTL", color="#FF0000")
|
4
|
+
print(tl) #=> {'name': 'PythonTL', 'color': '#FF0000', 'execute': True, 'shard': 0, 'scope': 'DEFAULT', 'updated_at': 1737129062249843763}
|
7
5
|
tls = list_timelines()
|
8
|
-
print(tls)
|
9
|
-
|
10
|
-
check_expression(f"{
|
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")
|
6
|
+
print(tls) #=> [{'name': 'PythonTL', 'color': '#FF0000', 'execute': True, 'shard': 0, 'scope': 'DEFAULT', 'updated_at': 1737129062249843763}]
|
7
|
+
names = [tl["name"] for tl in tls]
|
8
|
+
check_expression(f"{'PythonTL' in names} == True")
|
9
|
+
print(tls[0]) #=> {'name': 'PythonTL', 'color': '#FF0000', 'execute': True, 'shard': 0, 'scope': 'DEFAULT', 'updated_at': 1737129436186473255}
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
print(
|
20
|
-
get_timeline("Mine")
|
21
|
-
) # => {"name":"Mine", "color":"#4287f5", "scope":"DEFAULT", "updated_at":1698763720728596964}
|
11
|
+
set_timeline_color("PythonTL", "#4287f5")
|
12
|
+
print(get_timeline("PythonTL")) #=> {'name': 'PythonTL', 'color': '#4287f5', 'execute': True, 'shard': 0, 'scope': 'DEFAULT', 'updated_at': 1737129508391137136}
|
22
13
|
|
23
14
|
now = datetime.now(timezone.utc)
|
24
15
|
start = now + timedelta(hours=1)
|
25
|
-
stop = start + timedelta(hours=1)
|
26
|
-
|
27
|
-
print(
|
28
|
-
# {
|
29
|
-
#
|
30
|
-
#
|
16
|
+
stop = start + timedelta(hours=1)
|
17
|
+
act1 = create_timeline_activity("PythonTL", kind="reserve", start=start, stop=stop)
|
18
|
+
print(act1) # =>
|
19
|
+
# {'name': 'PythonTL', 'updated_at': 1737129305507111708, 'start': 1737132902, 'stop': 1737136502,
|
20
|
+
# 'kind': 'reserve', 'data': {'username': 'operator'},
|
21
|
+
# 'scope': 'DEFAULT', 'fulfillment': False, 'uuid': '46328378-ed78-4719-ad70-e84951a196fd',
|
22
|
+
# 'events': [{'time': 1737129305, 'event': 'created'}], 'recurring': {}}
|
23
|
+
act2 = create_timeline_activity("PythonTL", kind="COMMAND", start=start, stop=stop,
|
24
|
+
data={'command': "INST COLLECT with TYPE NORMAL, DURATION 5, TEMP 10"})
|
25
|
+
print(act2) #=>
|
26
|
+
# {'name': 'PythonTL', 'updated_at': 1737129508886643928, 'start': 1737133108, 'stop': 1737136708,
|
27
|
+
# 'kind': 'command', 'data': {'command': 'INST COLLECT with TYPE NORMAL, DURATION 5, TEMP 10', 'username': 'operator'},
|
28
|
+
# 'scope': 'DEFAULT', 'fulfillment': False, 'uuid': 'cddbf034-ccdd-4c36-91c2-2653a39b06a5',
|
29
|
+
# 'events': [{'time': 1737129508, 'event': 'created'}], 'recurring': {}}
|
30
|
+
start = now + timedelta(hours=2)
|
31
|
+
stop = start + timedelta(hours=1)
|
32
|
+
act3 = create_timeline_activity("PythonTL", kind="SCRIPT", start=start, stop=stop,
|
33
|
+
data={'environment': [{'key': "USER", 'value': "JASON"}], 'script': "INST2/procedures/checks.py"})
|
34
|
+
print(act3) #=>
|
35
|
+
# {'name': 'PythonTL', 'updated_at': 1737129509288571345, 'start': 1737136708, 'stop': 1737140308,
|
36
|
+
# 'kind': 'script', 'data': {'environment': [{'key': 'USER', 'value': 'JASON'}], 'script': 'INST2/procedures/checks.py', 'username': 'operator'},
|
37
|
+
# 'scope': 'DEFAULT', 'fulfillment': False, 'uuid': '4f8d791b-b138-4383-b5ec-85c28b2bea20',
|
38
|
+
# 'events': [{'time': 1737129509, 'event': 'created'}], 'recurring': {}}
|
39
|
+
|
40
|
+
act = get_timeline_activity("PythonTL", act2['start'], act2['uuid'])
|
41
|
+
print(act) #=>
|
42
|
+
# { "name"=>"RubyTL", "updated_at"=>1737128761316084471, "start"=>1737132303, "stop"=>1737135903,
|
43
|
+
# "kind"=>"command", "data"=>{"command"=>"INST COLLECT with TYPE NORMAL, DURATION 5, TEMP 10", "username"=>"operator"},
|
44
|
+
# "scope"=>"DEFAULT", "fulfillment"=>false, "uuid"=>"cdb661b4-a65b-44e7-95e2-5e1dba80c782",
|
45
|
+
# "events"=>[{"time"=>1737128761, "event"=>"created"}], "recurring"=>{}}
|
46
|
+
|
31
47
|
# Get activities in the past ... should be none
|
32
|
-
tlas = get_timeline_activities("
|
48
|
+
tlas = get_timeline_activities("PythonTL", start=now - timedelta(hours=2), stop=now)
|
33
49
|
print(tlas)
|
34
50
|
print(type(tlas))
|
35
51
|
check_expression(f"{len(tlas)} == 0")
|
36
|
-
# Get all activities
|
37
|
-
tlas = get_timeline_activities("
|
38
|
-
check_expression(f"{len(tlas)} ==
|
52
|
+
# Get all activities at plus and minus 1 week
|
53
|
+
tlas = get_timeline_activities("PythonTL")
|
54
|
+
check_expression(f"{len(tlas)} == 3")
|
39
55
|
|
40
56
|
# Create and delete a new activity
|
41
57
|
start = start + timedelta(hours=2)
|
42
58
|
stop = start + timedelta(minutes=30)
|
43
|
-
act = create_timeline_activity("
|
44
|
-
tlas = get_timeline_activities("
|
45
|
-
check_expression(f"{len(tlas)} ==
|
46
|
-
delete_timeline_activity("
|
47
|
-
tlas = get_timeline_activities("
|
48
|
-
check_expression(f"{len(tlas)} ==
|
59
|
+
act = create_timeline_activity("PythonTL", kind="reserve", start=start, stop=stop)
|
60
|
+
tlas = get_timeline_activities("PythonTL")
|
61
|
+
check_expression(f"{len(tlas)} == 4")
|
62
|
+
delete_timeline_activity("PythonTL", act["start"], act["uuid"])
|
63
|
+
tlas = get_timeline_activities("PythonTL")
|
64
|
+
check_expression(f"{len(tlas)} == 3")
|
49
65
|
|
50
66
|
# 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
|
67
|
+
delete_timeline("PythonTL")
|
54
68
|
# Force delete since the timeline has activities
|
55
|
-
delete_timeline("
|
69
|
+
delete_timeline("PythonTL", force=True)
|
56
70
|
tls = list_timelines()
|
57
|
-
|
71
|
+
names = [tl["name"] for tl in tls]
|
72
|
+
check_expression(f"{'PythonTL' in names} == False")
|
@@ -17,5 +17,5 @@ wait_expression("True == False", 5)
|
|
17
17
|
wait_packet("<%= target_name %>", "ADCS", 2, 5)
|
18
18
|
wait_check("<%= target_name %> ADCS BIASX == 100", 5)
|
19
19
|
wait_check_tolerance("<%= target_name %> ADCS BIASX", 5, 0.5, 5)
|
20
|
-
wait_check_expression("
|
20
|
+
wait_check_expression(f"tlm('<%= target_name %> HEALTH_STATUS TEMP1') < 101", 5, 0.25, globals())
|
21
21
|
wait_check_packet("<%= target_name %>", "ADCS", 2, 5)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Helper method to check for a script to change state
|
2
|
+
def wait_for_action(id, state):
|
3
|
+
i = 0
|
4
|
+
while i < 100:
|
5
|
+
script = running_script_get(id)
|
6
|
+
if script['state'] == state:
|
7
|
+
check_expression(f"'{script['state']}' == '{state}'")
|
8
|
+
break
|
9
|
+
wait(0.1)
|
10
|
+
check_expression(f"'{script['state']}' == '{state}'")
|
11
|
+
|
12
|
+
SCRIPT_NAME = "INST2/procedures/new_script.py"
|
13
|
+
|
14
|
+
# Ensure it's not already there
|
15
|
+
step_mode()
|
16
|
+
script_delete(SCRIPT_NAME)
|
17
|
+
scripts = script_list()
|
18
|
+
check_expression(f"{len(scripts)} > 100")
|
19
|
+
run_mode()
|
20
|
+
|
21
|
+
contents = "print('bad"
|
22
|
+
script_create(SCRIPT_NAME, contents)
|
23
|
+
body = script_body(SCRIPT_NAME)
|
24
|
+
result = script_syntax_check(body)
|
25
|
+
check_expression(f"{result['success']} == False")
|
26
|
+
|
27
|
+
contents = 'set_line_delay(1)\nprint("Hello from Python")\nprint(".")\nprint(".")\nwhile True:\n print(".")\n wait(0.5)\n wait(0.5)\n'
|
28
|
+
result = script_create(SCRIPT_NAME, contents)
|
29
|
+
scripts = script_list()
|
30
|
+
check_expression(f"{SCRIPT_NAME in scripts} == True")
|
31
|
+
|
32
|
+
script = script_instrumented(contents)
|
33
|
+
check_expression(f"{'RunningScript.instance' in script} == True")
|
34
|
+
|
35
|
+
id = script_run(SCRIPT_NAME)
|
36
|
+
check_expression(f"{int(id)} > 0")
|
37
|
+
wait_for_action(id, 'running')
|
38
|
+
|
39
|
+
list = running_script_list()
|
40
|
+
started = [script for script in list if script["id"] == id][0]
|
41
|
+
check_expression(f"'{started['name']}' == '{SCRIPT_NAME}'")
|
42
|
+
script = running_script_get(id)
|
43
|
+
check_expression(f"'{script['name']}' == '{SCRIPT_NAME}'")
|
44
|
+
|
45
|
+
running_script_pause(id)
|
46
|
+
wait_for_action(id, 'paused')
|
47
|
+
running_script_step(id)
|
48
|
+
wait_for_action(id, 'paused')
|
49
|
+
running_script_retry(id)
|
50
|
+
wait_for_action(id, 'paused')
|
51
|
+
running_script_go(id)
|
52
|
+
wait_for_action(id, 'running')
|
53
|
+
running_script_stop(id)
|
54
|
+
wait(1)
|
55
|
+
|
56
|
+
list = running_script_list()
|
57
|
+
script = [script for script in list if script["id"] == id]
|
58
|
+
# Script is stopped so it should NOT be in the running list
|
59
|
+
check_expression(f"{len(script)} == 0")
|
60
|
+
|
61
|
+
list = completed_script_list()
|
62
|
+
script = [script for script in list if script["id"] == id]
|
63
|
+
# Script is completed so it should be in the completed list
|
64
|
+
check_expression(f"{len(script)} == 1")
|
65
|
+
|
66
|
+
id = script_run(SCRIPT_NAME)
|
67
|
+
wait_for_action(id, 'running')
|
68
|
+
running_script_delete(id) # Stop and completely remove the script
|
69
|
+
wait(1)
|
70
|
+
|
71
|
+
list = running_script_list()
|
72
|
+
script = [script for script in list if script["id"] == id]
|
73
|
+
# Script is deleted, so it should NOT be in the running list
|
74
|
+
check_expression(f"{len(script)} == 0")
|
75
|
+
list = completed_script_list()
|
76
|
+
# Script is deleted so it should be in the completed list
|
77
|
+
script = [script for script in list if script["id"] == id]
|
78
|
+
check_expression(f"{len(script)} == 1")
|
79
|
+
|
80
|
+
script_lock(SCRIPT_NAME)
|
81
|
+
script_unlock(SCRIPT_NAME)
|
82
|
+
script_delete(SCRIPT_NAME)
|
83
|
+
scripts = script_list()
|
84
|
+
check_expression(f"{SCRIPT_NAME not in scripts} == True")
|