openc3 6.10.2 → 6.10.3
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/bin/openc3cli +11 -1
- data/data/config/item_modifiers.yaml +2 -2
- data/data/config/parameter_modifiers.yaml +2 -2
- data/data/config/screen.yaml +23 -0
- data/data/config/target.yaml +8 -3
- data/data/config/widgets.yaml +30 -0
- data/lib/openc3/accessors/json_accessor.rb +1 -1
- data/lib/openc3/api/tlm_api.rb +1 -6
- data/lib/openc3/io/json_api_object.rb +38 -14
- data/lib/openc3/io/json_drb_object.rb +29 -11
- data/lib/openc3/microservices/interface_microservice.rb +8 -3
- data/lib/openc3/models/target_model.rb +2 -1
- data/lib/openc3/packets/packet.rb +3 -0
- data/lib/openc3/packets/packet_config.rb +2 -2
- data/lib/openc3/packets/parsers/packet_item_parser.rb +9 -0
- data/lib/openc3/packets/parsers/xtce_converter.rb +464 -100
- data/lib/openc3/version.rb +5 -5
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +3 -3
- data/templates/widget/package.json +2 -2
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c1459e2b7d8160f09840d33a7fc6aa6314eb34367d68f41d45902a0203b37f57
|
|
4
|
+
data.tar.gz: 6de6d85032257c4e19f9470846056d5cf4aa8acc0498e4f9691543598a12856f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 556297be7a37dac84357e9a4c63c0c69a8c2fae6b0f8478317c9eb5b95506880f2b4acb2c99a56e4d7d2b0e4c4f22f4cf78a244046f027b68aad6b73a87a7845
|
|
7
|
+
data.tar.gz: e36738a22fcdcfbc136a899a051f691c29b8a0701b6c6a6f79d36c3f4689d4ea8018c01b90a5908b082a07507d14f2fce3ab252fcd5abc3a04312daf935f1cfc
|
data/bin/openc3cli
CHANGED
|
@@ -33,6 +33,7 @@ require 'openc3/models/queue_model'
|
|
|
33
33
|
require 'openc3/models/scope_model'
|
|
34
34
|
require 'openc3/models/tool_model'
|
|
35
35
|
require 'openc3/packets/packet_config'
|
|
36
|
+
require 'openc3/packets/parsers/xtce_converter'
|
|
36
37
|
require 'openc3/utilities/bucket'
|
|
37
38
|
require 'openc3/utilities/cli_generator'
|
|
38
39
|
require 'openc3/utilities/local_mode'
|
|
@@ -107,7 +108,8 @@ def xtce_converter(args)
|
|
|
107
108
|
options = {}
|
|
108
109
|
option_parser = OptionParser.new do |opts|
|
|
109
110
|
opts.banner = "Usage: xtce_converter [options] --import input_xtce_filename --output output_dir\n"+
|
|
110
|
-
" xtce_converter [options] --plugin /PATH/FILENAME.gem --output output_dir
|
|
111
|
+
" xtce_converter [options] --plugin /PATH/FILENAME.gem --output output_dir "+
|
|
112
|
+
" --variables variables.txt --root_target root_target_name --time_association_name time_association_name"
|
|
111
113
|
opts.separator("")
|
|
112
114
|
opts.on("-h", "--help", "Show this message") do
|
|
113
115
|
puts opts
|
|
@@ -125,6 +127,12 @@ def xtce_converter(args)
|
|
|
125
127
|
opts.on("-v", "--variables", "Optional variables file to pass to the plugin") do |arg|
|
|
126
128
|
options[:variables] = arg
|
|
127
129
|
end
|
|
130
|
+
opts.on("-r ROOT_TARGET", "--root_target ROOT_TARGET", "Optional flag to set which target is at the root of an XTCE document. If not specified, each target will be placed under a generic 'root' spacesystem") do |arg|
|
|
131
|
+
options[:root_target_name] = arg
|
|
132
|
+
end
|
|
133
|
+
opts.on("-t TIME_ASSOCIATION_NAME", "--time_association_name TIME_ASSOCIATION_NAME", "Optional flag to set which target is at the root of an XTCE document. If not specified, each target will be placed under a generic 'root' spacesystem") do |arg|
|
|
134
|
+
options[:time_association_name] = "PACKET_TIME"
|
|
135
|
+
end
|
|
128
136
|
end
|
|
129
137
|
|
|
130
138
|
begin
|
|
@@ -156,8 +164,10 @@ def xtce_converter(args)
|
|
|
156
164
|
puts "Installing #{File.basename(options[:plugin])}"
|
|
157
165
|
plugin_hash = OpenC3::PluginModel.install_phase1(options[:plugin], existing_variables: variables, scope: 'DEFAULT', validate_only: true)
|
|
158
166
|
plugin_hash['variables']['xtce_output'] = options[:output]
|
|
167
|
+
plugin_hash['variables']['time_association_name'] = options[:time_association_name]
|
|
159
168
|
OpenC3::PluginModel.install_phase2(plugin_hash, scope: 'DEFAULT', validate_only: true,
|
|
160
169
|
gem_file_path: options[:plugin])
|
|
170
|
+
OpenC3::XtceConverter.combine_output_xtce(options[:output], options[:root_target_name])
|
|
161
171
|
result = 0 # bash and Windows consider 0 success
|
|
162
172
|
rescue => e
|
|
163
173
|
puts "Error: #{e.message}"
|
|
@@ -79,12 +79,12 @@ GENERIC_READ_CONVERSION_START:
|
|
|
79
79
|
ruby_example: |
|
|
80
80
|
APPEND_ITEM ITEM1 32 UINT
|
|
81
81
|
GENERIC_READ_CONVERSION_START
|
|
82
|
-
|
|
82
|
+
(value * 1.5).to_i # Convert the value by a scale factor
|
|
83
83
|
GENERIC_READ_CONVERSION_END
|
|
84
84
|
python_example: |
|
|
85
85
|
APPEND_ITEM ITEM1 32 UINT
|
|
86
86
|
GENERIC_READ_CONVERSION_START
|
|
87
|
-
|
|
87
|
+
int(value * 1.5) # Convert the value by a scale factor
|
|
88
88
|
GENERIC_READ_CONVERSION_END
|
|
89
89
|
parameters:
|
|
90
90
|
- name: Converted Type
|
|
@@ -141,12 +141,12 @@ GENERIC_WRITE_CONVERSION_START:
|
|
|
141
141
|
ruby_example: |
|
|
142
142
|
APPEND_PARAMETER ITEM1 32 UINT 0 0xFFFFFFFF 0
|
|
143
143
|
GENERIC_WRITE_CONVERSION_START
|
|
144
|
-
|
|
144
|
+
(value * 1.5).to_i # Convert the value by a scale factor
|
|
145
145
|
GENERIC_WRITE_CONVERSION_END
|
|
146
146
|
python_example: |
|
|
147
147
|
APPEND_PARAMETER ITEM1 32 UINT 0 0xFFFFFFFF 0
|
|
148
148
|
GENERIC_WRITE_CONVERSION_START
|
|
149
|
-
|
|
149
|
+
int(value * 1.5) # Convert the value by a scale factor
|
|
150
150
|
GENERIC_WRITE_CONVERSION_END
|
|
151
151
|
GENERIC_WRITE_CONVERSION_END:
|
|
152
152
|
summary: Complete a generic write conversion
|
data/data/config/screen.yaml
CHANGED
|
@@ -125,6 +125,29 @@ SUBSETTING:
|
|
|
125
125
|
LABELVALUELIMITSBAR INST HEALTH_STATUS TEMP1
|
|
126
126
|
SUBSETTING 0 TEXTCOLOR green # Change the label's text to green
|
|
127
127
|
END
|
|
128
|
+
TOOLTIP:
|
|
129
|
+
summary: Adds a tooltip to the previously defined widget
|
|
130
|
+
description: TOOLTIP applies a custom hover tooltip to the widget defined immediately before it.
|
|
131
|
+
This allows you to provide helpful descriptions, mnemonics, or other contextual information
|
|
132
|
+
that appears when the user hovers over a widget. The tooltip overrides any default tooltip
|
|
133
|
+
that the widget may have.
|
|
134
|
+
since: 6.10.3
|
|
135
|
+
parameters:
|
|
136
|
+
- name: Tooltip Text
|
|
137
|
+
required: true
|
|
138
|
+
description: The text to display in the tooltip when hovering over the widget.
|
|
139
|
+
values: .+
|
|
140
|
+
- name: Delay
|
|
141
|
+
required: false
|
|
142
|
+
description: The delay in milliseconds before the tooltip appears (default = 600).
|
|
143
|
+
values: \d+
|
|
144
|
+
example: |
|
|
145
|
+
LED INST PARAMS VALUE5 RAW 25 20
|
|
146
|
+
SETTING LED_COLOR 0 GREEN
|
|
147
|
+
SETTING LED_COLOR 1 RED
|
|
148
|
+
TOOLTIP "Mnemonic: ABCDEF. This is the Star Tracker On/Off Status"
|
|
149
|
+
VALUE INST HEALTH_STATUS TEMP1
|
|
150
|
+
TOOLTIP "Temperature sensor 1: Primary thermal control" 1000
|
|
128
151
|
NAMED_WIDGET:
|
|
129
152
|
summary: Name a widget to allow access to it via the getNamedWidget method
|
|
130
153
|
description: To programmatically access parts of a telemetry screen you need
|
data/data/config/target.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
TARGET:
|
|
3
3
|
summary: Defines a new target
|
|
4
|
-
example: TARGET
|
|
4
|
+
example: TARGET KEYSIGHT_N6700 PWR_SUPPLY1
|
|
5
5
|
parameters:
|
|
6
6
|
- name: Folder Name
|
|
7
7
|
required: true
|
|
@@ -10,8 +10,13 @@ TARGET:
|
|
|
10
10
|
- name: Name
|
|
11
11
|
required: true
|
|
12
12
|
description:
|
|
13
|
-
The target name. While this
|
|
14
|
-
it can be different to create multiple targets based on the same target
|
|
13
|
+
The target name. While this typically matches the Folder Name
|
|
14
|
+
it can be different to create multiple targets based on the same target definition.
|
|
15
|
+
As in the Example Usage, the target folder is KEYSIGHT_N6700 but the target name is PWR_SUPPLY1.
|
|
16
|
+
To create multiple targets from the same folder, just define multiple TARGET entries
|
|
17
|
+
with different target names. To make the target definition flexbible, you can use ERB to
|
|
18
|
+
insert the target name in procedures, libraries, etc via <%= target_name %>.
|
|
19
|
+
See [ERB target_name](/docs/configuration/format#target_name) for more information.
|
|
15
20
|
values: .*
|
|
16
21
|
modifiers:
|
|
17
22
|
CMD_BUFFER_DEPTH:
|
data/data/config/widgets.yaml
CHANGED
|
@@ -204,6 +204,36 @@ Decoration Widgets:
|
|
|
204
204
|
SPACER 0 100
|
|
205
205
|
LABEL "Spacer above"
|
|
206
206
|
END
|
|
207
|
+
FILEDISPLAY:
|
|
208
|
+
summary: Displays the contents of a target file with syntax highlighting
|
|
209
|
+
since: 6.10.3
|
|
210
|
+
parameters:
|
|
211
|
+
- name: File path
|
|
212
|
+
required: true
|
|
213
|
+
description: Path to the file relative to the target folder (e.g. "INST/procedures/file.rb")
|
|
214
|
+
values: .+
|
|
215
|
+
- name: Width
|
|
216
|
+
required: false
|
|
217
|
+
description: Width of the widget in pixels (default = 600)
|
|
218
|
+
values: \d+
|
|
219
|
+
- name: Height
|
|
220
|
+
required: false
|
|
221
|
+
description: Height of the widget in pixels (default = 300)
|
|
222
|
+
values: \d+
|
|
223
|
+
example: |
|
|
224
|
+
FILEDISPLAY "INST/data/sample.json" 400 200
|
|
225
|
+
FILECHECKSUM:
|
|
226
|
+
summary: Displays SHA-256 checksum of one or more files, with comparison if multiple
|
|
227
|
+
since: 6.10.3
|
|
228
|
+
parameters:
|
|
229
|
+
- name: File path
|
|
230
|
+
required: true
|
|
231
|
+
description: Path to a file relative to the target folder (e.g. "INST/procedures/file.rb"). Multiple file paths can be provided to compare checksums.
|
|
232
|
+
values: .+
|
|
233
|
+
example: |
|
|
234
|
+
FILECHECKSUM "INST/data/sample.json"
|
|
235
|
+
FILECHECKSUM "INST/data/sample.json" "INST2/data/sample.json"
|
|
236
|
+
FILECHECKSUM "INST/data/file1.bin" "INST/data/file2.bin" "INST/data/file3.bin"
|
|
207
237
|
Telemetry Widgets:
|
|
208
238
|
description: Telemetry widgets are used to display telemetry values.
|
|
209
239
|
The first parameters to each of these widgets is a telemetry mnemonic.
|
|
@@ -25,7 +25,7 @@ require 'openc3/accessors/accessor'
|
|
|
25
25
|
OpenC3.disable_warnings do
|
|
26
26
|
class JsonPath
|
|
27
27
|
def self.process_object(obj_or_str, opts = {})
|
|
28
|
-
obj_or_str.is_a?(String) ? MultiJson.
|
|
28
|
+
obj_or_str.is_a?(String) ? MultiJson.load(obj_or_str, max_nesting: opts[:max_nesting], create_additions: true, allow_nan: true) : obj_or_str
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
end
|
data/lib/openc3/api/tlm_api.rb
CHANGED
|
@@ -284,13 +284,8 @@ module OpenC3
|
|
|
284
284
|
value_type = 'RAW' # Must request the raw value when dealing with the reserved items
|
|
285
285
|
end
|
|
286
286
|
|
|
287
|
-
#
|
|
287
|
+
# Arrays must be accessed as RAW since there's no conversion
|
|
288
288
|
if item['array_size']
|
|
289
|
-
# TODO: This needs work ... we're JSON encoding non numeric array values
|
|
290
|
-
if item['data_type'] == 'STRING' or item['data_type'] == 'BLOCK'
|
|
291
|
-
results << nil
|
|
292
|
-
next
|
|
293
|
-
end
|
|
294
289
|
value_type = 'RAW'
|
|
295
290
|
end
|
|
296
291
|
|
|
@@ -34,6 +34,10 @@ require 'faraday'
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
module OpenC3
|
|
37
|
+
# Number of times to retry a request when a connection error occurs
|
|
38
|
+
RETRY_COUNT = 3
|
|
39
|
+
# Delay between retries in seconds
|
|
40
|
+
RETRY_DELAY = 0.1
|
|
37
41
|
|
|
38
42
|
class JsonApiError < StandardError; end
|
|
39
43
|
|
|
@@ -200,21 +204,41 @@ module OpenC3
|
|
|
200
204
|
|
|
201
205
|
# NOTE: This is a helper method and should not be called directly
|
|
202
206
|
def _send_request(method:, endpoint:, kwargs:)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
uri = URI("#{@url}#{endpoint}")
|
|
208
|
+
@log[0] = "#{method} Request: #{uri.to_s} #{kwargs}"
|
|
209
|
+
STDOUT.puts @log[0] if JsonDRb.debug?
|
|
210
|
+
|
|
211
|
+
retry_count = 0
|
|
212
|
+
while retry_count <= RETRY_COUNT
|
|
213
|
+
begin
|
|
214
|
+
resp = _http_request(method: method, uri: uri, kwargs: kwargs)
|
|
215
|
+
@log[1] = "#{method} Response: #{resp.status} #{resp.headers} #{resp.body}"
|
|
216
|
+
STDOUT.puts @log[1] if JsonDRb.debug?
|
|
217
|
+
@response_data = resp.body
|
|
218
|
+
return resp
|
|
219
|
+
rescue Faraday::ConnectionFailed, Errno::ECONNRESET, Errno::EPIPE, IOError => e
|
|
220
|
+
# Connection errors are retryable - reconnect and try again
|
|
221
|
+
retry_count += 1
|
|
222
|
+
@log[2] = "#{method} Exception: #{e.class}, #{e.message}, #{e.backtrace}"
|
|
223
|
+
if retry_count <= RETRY_COUNT
|
|
224
|
+
Logger.warn("JsonApiObject: Connection error, retry #{retry_count}/#{RETRY_COUNT}: #{e.class} #{e.message}")
|
|
225
|
+
disconnect()
|
|
226
|
+
sleep(RETRY_DELAY)
|
|
227
|
+
connect()
|
|
228
|
+
else
|
|
229
|
+
error = "Api Exception: #{@log[0]} ::: #{@log[1]} ::: #{@log[2]}"
|
|
230
|
+
raise error
|
|
231
|
+
end
|
|
232
|
+
rescue StandardError => e
|
|
233
|
+
@log[2] = "#{method} Exception: #{e.class}, #{e.message}, #{e.backtrace}"
|
|
234
|
+
disconnect()
|
|
235
|
+
error = "Api Exception: #{@log[0]} ::: #{@log[1]} ::: #{@log[2]}"
|
|
236
|
+
raise error
|
|
237
|
+
end
|
|
217
238
|
end
|
|
239
|
+
# Should not reach here, but just in case
|
|
240
|
+
error = "Api Exception: #{@log[0]} ::: #{@log[1]} ::: #{@log[2]}"
|
|
241
|
+
raise error
|
|
218
242
|
end
|
|
219
243
|
|
|
220
244
|
# NOTE: This is a helper method and should not be called directly
|
|
@@ -92,18 +92,36 @@ module OpenC3
|
|
|
92
92
|
'Content-Type' => 'application/json-rpc',
|
|
93
93
|
}
|
|
94
94
|
end
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
95
|
+
|
|
96
|
+
@log[0] = "Request: #{@uri.to_s} #{USER_AGENT} #{data.to_s}"
|
|
97
|
+
STDOUT.puts @log[0] if JsonDRb.debug?
|
|
98
|
+
|
|
99
|
+
retry_count = 0
|
|
100
|
+
while retry_count <= RETRY_COUNT
|
|
101
|
+
begin
|
|
102
|
+
resp = @http.post(@uri, data, headers)
|
|
103
|
+
@log[1] = "Response: #{resp.status} #{resp.headers} #{resp.body}"
|
|
104
|
+
@response_data = resp.body
|
|
105
|
+
STDOUT.puts @log[1] if JsonDRb.debug?
|
|
106
|
+
return resp.body
|
|
107
|
+
rescue Faraday::ConnectionFailed, Errno::ECONNRESET, Errno::EPIPE, IOError => e
|
|
108
|
+
# Connection errors are retryable - reconnect and try again
|
|
109
|
+
retry_count += 1
|
|
110
|
+
@log[2] = "Exception: #{e.class}, #{e.message}, #{e.backtrace}"
|
|
111
|
+
if retry_count <= RETRY_COUNT
|
|
112
|
+
Logger.warn("JsonDRbObject: Connection error, retry #{retry_count}/#{RETRY_COUNT}: #{e.class} #{e.message}")
|
|
113
|
+
disconnect()
|
|
114
|
+
sleep(RETRY_DELAY)
|
|
115
|
+
connect()
|
|
116
|
+
else
|
|
117
|
+
return nil
|
|
118
|
+
end
|
|
119
|
+
rescue StandardError => e
|
|
120
|
+
@log[2] = "Exception: #{e.class}, #{e.message}, #{e.backtrace}"
|
|
121
|
+
return nil
|
|
122
|
+
end
|
|
106
123
|
end
|
|
124
|
+
return nil
|
|
107
125
|
end
|
|
108
126
|
|
|
109
127
|
def handle_response(response:)
|
|
@@ -89,6 +89,7 @@ module OpenC3
|
|
|
89
89
|
InterfaceTopic.receive_commands(@interface, scope: @scope) do |topic, msg_id, msg_hash, _redis|
|
|
90
90
|
OpenC3.with_context(msg_hash) do
|
|
91
91
|
release_critical = false
|
|
92
|
+
critical_model = nil
|
|
92
93
|
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
|
|
93
94
|
delta = Time.now.to_f - msgid_seconds_from_epoch
|
|
94
95
|
@metric.set(name: 'interface_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and interface cmd start') if @metric
|
|
@@ -188,9 +189,9 @@ module OpenC3
|
|
|
188
189
|
end
|
|
189
190
|
if msg_hash.key?('release_critical')
|
|
190
191
|
# Note: intentional fall through below this point
|
|
191
|
-
|
|
192
|
-
if
|
|
193
|
-
msg_hash =
|
|
192
|
+
critical_model = CriticalCmdModel.get_model(name: msg_hash['release_critical'], scope: @scope)
|
|
193
|
+
if critical_model
|
|
194
|
+
msg_hash = critical_model.cmd_hash
|
|
194
195
|
release_critical = true
|
|
195
196
|
else
|
|
196
197
|
next "Critical command #{msg_hash['release_critical']} not found"
|
|
@@ -279,6 +280,10 @@ module OpenC3
|
|
|
279
280
|
command.extra ||= {}
|
|
280
281
|
command.extra['cmd_string'] = msg_hash['cmd_string']
|
|
281
282
|
command.extra['username'] = msg_hash['username']
|
|
283
|
+
# Add approver info if this was a critical command that was approved
|
|
284
|
+
if critical_model
|
|
285
|
+
command.extra['approver'] = critical_model.approver
|
|
286
|
+
end
|
|
282
287
|
hazardous, hazardous_description = System.commands.cmd_pkt_hazardous?(command)
|
|
283
288
|
|
|
284
289
|
# Initial Are you sure? Hazardous check
|
|
@@ -638,7 +638,8 @@ module OpenC3
|
|
|
638
638
|
system = System.new([@name], temp_dir)
|
|
639
639
|
if variables["xtce_output"]
|
|
640
640
|
puts "Converting target #{@name} to .xtce files in #{variables["xtce_output"]}/#{@name}"
|
|
641
|
-
|
|
641
|
+
puts " Using mnemonic '#{variables['time_association_name']}' as the packet time item."
|
|
642
|
+
system.packet_config.to_xtce(variables["xtce_output"], variables['time_association_name'])
|
|
642
643
|
end
|
|
643
644
|
unless validate_only
|
|
644
645
|
build_target_archive(temp_dir, target_folder)
|
|
@@ -433,6 +433,9 @@ module OpenC3
|
|
|
433
433
|
previous_item = nil
|
|
434
434
|
warnings = []
|
|
435
435
|
@sorted_items.each do |item|
|
|
436
|
+
# Skip items with a parent_item since those are accessor-based items within a structure
|
|
437
|
+
# (e.g., JSON, CBOR) that don't have meaningful bit positions - they share the parent's bit_offset
|
|
438
|
+
next if item.parent_item
|
|
436
439
|
if expected_next_offset and (item.bit_offset < expected_next_offset) and !item.overlap
|
|
437
440
|
msg = "Bit definition overlap at bit offset #{item.bit_offset} for packet #{@target_name} #{@packet_name} items #{item.name} and #{previous_item.name}"
|
|
438
441
|
Logger.instance.warn(msg)
|
|
@@ -331,8 +331,8 @@ module OpenC3
|
|
|
331
331
|
end
|
|
332
332
|
end # def to_config
|
|
333
333
|
|
|
334
|
-
def to_xtce(output_dir)
|
|
335
|
-
XtceConverter.convert(@commands, @telemetry, output_dir)
|
|
334
|
+
def to_xtce(output_dir, time_association_name)
|
|
335
|
+
XtceConverter.convert(@commands, @telemetry, output_dir, time_association_name)
|
|
336
336
|
end
|
|
337
337
|
|
|
338
338
|
# Add current packet into hash if it exists
|
|
@@ -65,6 +65,15 @@ module OpenC3
|
|
|
65
65
|
@parser.verify_num_parameters(max_options - 2, max_options, @usage)
|
|
66
66
|
end
|
|
67
67
|
@parser.verify_parameter_naming(1) # Item name is the 1st parameter
|
|
68
|
+
|
|
69
|
+
# ARRAY items cannot have brackets in their name because brackets are used
|
|
70
|
+
# for array indexing in the UI and would cause confusion
|
|
71
|
+
if @parser.keyword.include?('ARRAY')
|
|
72
|
+
item_name = @parser.parameters[0]
|
|
73
|
+
if item_name.include?('[') || item_name.include?(']')
|
|
74
|
+
raise @parser.error("ARRAY items cannot have brackets in their name: #{item_name}", @usage)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
68
77
|
end
|
|
69
78
|
|
|
70
79
|
def create_packet_item(packet, cmd_or_tlm)
|