openc3 5.18.0 → 5.19.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/Gemfile +7 -4
- data/bin/cstol_converter +14 -14
- data/bin/openc3cli +189 -7
- data/data/config/_interfaces.yaml +1 -1
- data/data/config/command_modifiers.yaml +55 -0
- data/data/config/interface_modifiers.yaml +1 -1
- data/data/config/param_item_modifiers.yaml +1 -1
- data/data/config/parameter_modifiers.yaml +1 -1
- data/data/config/plugins.yaml +6 -2
- data/data/config/screen.yaml +2 -2
- data/data/config/table_manager.yaml +2 -2
- data/data/config/tool.yaml +4 -1
- data/data/config/widgets.yaml +3 -3
- data/ext/openc3/ext/config_parser/config_parser.c +1 -1
- data/ext/openc3/ext/packet/packet.c +1 -1
- data/ext/openc3/ext/platform/platform.c +3 -3
- data/ext/openc3/ext/structure/structure.c +56 -76
- data/lib/openc3/accessors/binary_accessor.rb +4 -4
- data/lib/openc3/accessors/form_accessor.rb +2 -2
- data/lib/openc3/accessors/http_accessor.rb +1 -1
- data/lib/openc3/accessors/json_accessor.rb +6 -4
- data/lib/openc3/accessors/template_accessor.rb +6 -9
- data/lib/openc3/accessors/xml_accessor.rb +1 -1
- data/lib/openc3/api/cmd_api.rb +35 -11
- data/lib/openc3/api/limits_api.rb +1 -1
- data/lib/openc3/config/config_parser.rb +1 -1
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +7 -7
- data/lib/openc3/core_ext/array.rb +5 -5
- data/lib/openc3/core_ext/exception.rb +9 -2
- data/lib/openc3/core_ext/string.rb +2 -2
- data/lib/openc3/interfaces/http_server_interface.rb +1 -0
- data/lib/openc3/interfaces/interface.rb +1 -1
- data/lib/openc3/interfaces/linc_interface.rb +3 -3
- data/lib/openc3/io/json_api.rb +11 -6
- data/lib/openc3/io/json_rpc.rb +1 -1
- data/lib/openc3/logs/buffered_packet_log_writer.rb +3 -3
- data/lib/openc3/logs/log_writer.rb +7 -8
- data/lib/openc3/logs/packet_log_writer.rb +7 -7
- data/lib/openc3/logs/text_log_writer.rb +4 -4
- data/lib/openc3/microservices/decom_microservice.rb +19 -4
- data/lib/openc3/microservices/interface_microservice.rb +41 -3
- data/lib/openc3/microservices/reaction_microservice.rb +2 -2
- data/lib/openc3/microservices/trigger_group_microservice.rb +3 -3
- data/lib/openc3/migrations/20240915000000_activity_uuid.rb +28 -0
- data/lib/openc3/models/activity_model.rb +109 -80
- data/lib/openc3/models/auth_model.rb +31 -2
- data/lib/openc3/models/cvt_model.rb +11 -5
- data/lib/openc3/models/gem_model.rb +8 -8
- data/lib/openc3/models/plugin_model.rb +3 -3
- data/lib/openc3/models/reducer_model.rb +2 -2
- data/lib/openc3/models/scope_model.rb +1 -1
- data/lib/openc3/models/sorted_model.rb +4 -4
- data/lib/openc3/models/target_model.rb +3 -3
- data/lib/openc3/models/tool_config_model.rb +1 -1
- data/lib/openc3/models/tool_model.rb +4 -4
- data/lib/openc3/models/widget_model.rb +11 -5
- data/lib/openc3/operators/operator.rb +5 -3
- data/lib/openc3/packets/command_validator.rb +48 -0
- data/lib/openc3/packets/commands.rb +6 -14
- data/lib/openc3/packets/packet.rb +31 -15
- data/lib/openc3/packets/packet_config.rb +10 -9
- data/lib/openc3/packets/parsers/packet_parser.rb +3 -3
- data/lib/openc3/packets/structure.rb +21 -13
- data/lib/openc3/packets/structure_item.rb +33 -47
- data/lib/openc3/packets/telemetry.rb +6 -27
- data/lib/openc3/script/api_shared.rb +7 -5
- data/lib/openc3/script/calendar.rb +2 -2
- data/lib/openc3/script/commands.rb +6 -4
- data/lib/openc3/script/metadata.rb +2 -2
- data/lib/openc3/script/suite.rb +17 -17
- data/lib/openc3/streams/serial_stream.rb +2 -3
- data/lib/openc3/streams/stream.rb +2 -2
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +10 -10
- data/lib/openc3/tools/table_manager/table_manager_core.rb +11 -11
- data/lib/openc3/tools/table_manager/table_parser.rb +2 -3
- data/lib/openc3/topics/command_decom_topic.rb +2 -1
- data/lib/openc3/topics/command_topic.rb +3 -3
- data/lib/openc3/topics/decom_interface_topic.rb +2 -2
- data/lib/openc3/topics/telemetry_decom_topic.rb +1 -1
- data/lib/openc3/utilities/authorization.rb +2 -1
- data/lib/openc3/utilities/cli_generator.rb +15 -8
- data/lib/openc3/utilities/cosmos_rails_formatter.rb +60 -0
- data/lib/openc3/utilities/crc.rb +6 -6
- data/lib/openc3/utilities/local_mode.rb +2 -1
- data/lib/openc3/utilities/logger.rb +44 -34
- data/lib/openc3/utilities/metric.rb +1 -2
- data/lib/openc3/utilities/quaternion.rb +18 -18
- data/lib/openc3/utilities/target_file.rb +4 -4
- data/lib/openc3/version.rb +5 -5
- data/lib/openc3/win32/win32_main.rb +2 -2
- data/templates/tool_angular/package.json +21 -21
- data/templates/tool_react/package.json +10 -10
- data/templates/tool_svelte/package.json +11 -11
- data/templates/tool_svelte/src/services/openc3-api.js +17 -17
- data/templates/tool_vue/package.json +9 -9
- data/templates/widget/package.json +6 -7
- metadata +5 -2
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
require 'openc3/logs/packet_log_writer'
|
|
20
20
|
|
|
21
21
|
module OpenC3
|
|
22
|
-
# Creates a packet log. Can automatically cycle the log based on an
|
|
22
|
+
# Creates a packet log. Can automatically cycle the log based on an elapsed
|
|
23
23
|
# time period or when the log file reaches a predefined size.
|
|
24
24
|
class BufferedPacketLogWriter < PacketLogWriter
|
|
25
25
|
# @param remote_log_directory [String] The path to store the log files
|
|
@@ -123,8 +123,8 @@ module OpenC3
|
|
|
123
123
|
@buffer.each do |entry|
|
|
124
124
|
write(*entry[0..-3], allow_new_file: false, take_mutex: false, received_time_nsec_since_epoch: entry[-2], extra: entry[-1])
|
|
125
125
|
end
|
|
126
|
-
rescue =>
|
|
127
|
-
Logger.instance.error "Error writing out buffer : #{
|
|
126
|
+
rescue => e
|
|
127
|
+
Logger.instance.error "Error writing out buffer : #{e.formatted}"
|
|
128
128
|
end
|
|
129
129
|
@buffer = []
|
|
130
130
|
end
|
|
@@ -20,13 +20,12 @@
|
|
|
20
20
|
# This file may also be used under the terms of a commercial license
|
|
21
21
|
# if purchased from OpenC3, Inc.
|
|
22
22
|
|
|
23
|
-
require 'thread'
|
|
24
23
|
require 'openc3/config/config_parser'
|
|
25
24
|
require 'openc3/topics/topic'
|
|
26
25
|
require 'openc3/utilities/bucket_utilities'
|
|
27
26
|
|
|
28
27
|
module OpenC3
|
|
29
|
-
# Creates a log. Can automatically cycle the log based on an
|
|
28
|
+
# Creates a log. Can automatically cycle the log based on an elapsed
|
|
30
29
|
# time period or when the log file reaches a predefined size.
|
|
31
30
|
class LogWriter
|
|
32
31
|
# @return [String] The filename of the packet log
|
|
@@ -275,10 +274,10 @@ module OpenC3
|
|
|
275
274
|
@last_time = nil
|
|
276
275
|
@previous_time_nsec_since_epoch = nil
|
|
277
276
|
Logger.debug "Log File Opened : #{@filename}"
|
|
278
|
-
rescue =>
|
|
279
|
-
Logger.error "Error starting new log file: #{
|
|
277
|
+
rescue => e
|
|
278
|
+
Logger.error "Error starting new log file: #{e.formatted}"
|
|
280
279
|
@logging_enabled = false
|
|
281
|
-
OpenC3.handle_critical_exception(
|
|
280
|
+
OpenC3.handle_critical_exception(e)
|
|
282
281
|
end
|
|
283
282
|
|
|
284
283
|
# @enforce_time_order requires the timestamps on each write to be greater than the previous
|
|
@@ -328,10 +327,10 @@ module OpenC3
|
|
|
328
327
|
@last_offsets.each do |redis_topic, last_offset|
|
|
329
328
|
@cleanup_offsets[-1][redis_topic] = last_offset
|
|
330
329
|
end
|
|
331
|
-
@cleanup_times << Time.now + CLEANUP_DELAY
|
|
330
|
+
@cleanup_times << (Time.now + CLEANUP_DELAY)
|
|
332
331
|
@last_offsets.clear
|
|
333
|
-
rescue Exception =>
|
|
334
|
-
Logger.error "Error closing #{@filename} : #{
|
|
332
|
+
rescue Exception => e
|
|
333
|
+
Logger.error "Error closing #{@filename} : #{e.formatted}"
|
|
335
334
|
end
|
|
336
335
|
|
|
337
336
|
@file = nil
|
|
@@ -26,7 +26,7 @@ require 'openc3/models/target_model'
|
|
|
26
26
|
require 'cbor'
|
|
27
27
|
|
|
28
28
|
module OpenC3
|
|
29
|
-
# Creates a packet log. Can automatically cycle the log based on an
|
|
29
|
+
# Creates a packet log. Can automatically cycle the log based on an elapsed
|
|
30
30
|
# time period or when the log file reaches a predefined size.
|
|
31
31
|
class PacketLogWriter < LogWriter
|
|
32
32
|
include PacketLogConstants
|
|
@@ -112,9 +112,9 @@ module OpenC3
|
|
|
112
112
|
ensure
|
|
113
113
|
@mutex.unlock if take_mutex
|
|
114
114
|
end
|
|
115
|
-
rescue =>
|
|
116
|
-
Logger.instance.error "Error writing #{@filename} : #{
|
|
117
|
-
OpenC3.handle_critical_exception(
|
|
115
|
+
rescue => e
|
|
116
|
+
Logger.instance.error "Error writing #{@filename} : #{e.formatted}"
|
|
117
|
+
OpenC3.handle_critical_exception(e)
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
# Starting a new file is a critical operation so the entire method is
|
|
@@ -133,10 +133,10 @@ module OpenC3
|
|
|
133
133
|
@next_target_index = 0
|
|
134
134
|
@target_dec_entries = []
|
|
135
135
|
@packet_dec_entries = []
|
|
136
|
-
rescue =>
|
|
137
|
-
Logger.error "Error starting new log file: #{
|
|
136
|
+
rescue => e
|
|
137
|
+
Logger.error "Error starting new log file: #{e.formatted}"
|
|
138
138
|
@logging_enabled = false
|
|
139
|
-
OpenC3.handle_critical_exception(
|
|
139
|
+
OpenC3.handle_critical_exception(e)
|
|
140
140
|
end
|
|
141
141
|
|
|
142
142
|
# Closing a log file isn't critical so we just log an error
|
|
@@ -24,7 +24,7 @@ require 'openc3/logs/log_writer'
|
|
|
24
24
|
require 'socket'
|
|
25
25
|
|
|
26
26
|
module OpenC3
|
|
27
|
-
# Creates a text log. Can automatically cycle the log based on an
|
|
27
|
+
# Creates a text log. Can automatically cycle the log based on an elapsed
|
|
28
28
|
# time period or when the log file reaches a predefined size.
|
|
29
29
|
class TextLogWriter < LogWriter
|
|
30
30
|
NEWLINE = "\n".freeze
|
|
@@ -48,9 +48,9 @@ module OpenC3
|
|
|
48
48
|
prepare_write(time_nsec_since_epoch, data.length, redis_topic, redis_offset)
|
|
49
49
|
write_entry(time_nsec_since_epoch, data) if @file
|
|
50
50
|
end
|
|
51
|
-
rescue =>
|
|
52
|
-
Logger.instance.error "Error writing #{@filename} : #{
|
|
53
|
-
OpenC3.handle_critical_exception(
|
|
51
|
+
rescue => e
|
|
52
|
+
Logger.instance.error "Error writing #{@filename} : #{e.formatted}"
|
|
53
|
+
OpenC3.handle_critical_exception(e)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def write_entry(time_nsec_since_epoch, data)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# GNU Affero General Public License for more details.
|
|
15
15
|
|
|
16
16
|
# Modified by OpenC3, Inc.
|
|
17
|
-
# All changes Copyright
|
|
17
|
+
# All changes Copyright 2024, OpenC3, Inc.
|
|
18
18
|
# All Rights Reserved
|
|
19
19
|
#
|
|
20
20
|
# This file may also be used under the terms of a commercial license
|
|
@@ -102,9 +102,22 @@ module OpenC3
|
|
|
102
102
|
packet.extra = extra
|
|
103
103
|
end
|
|
104
104
|
packet.buffer = msg_hash["buffer"]
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
# Processors are user code points which must be rescued
|
|
106
|
+
# so the TelemetryDecomTopic can write the packet
|
|
107
|
+
begin
|
|
108
|
+
packet.process # Run processors
|
|
109
|
+
rescue Exception => e
|
|
110
|
+
@error_count += 1
|
|
111
|
+
@metric.set(name: 'decom_error_total', value: @error_count, type: 'counter')
|
|
112
|
+
@error = e
|
|
113
|
+
@logger.error e.message
|
|
114
|
+
end
|
|
115
|
+
# Process all the limits and call the limits_change_callback (as necessary)
|
|
116
|
+
# check_limits also can call user code in the limits response
|
|
117
|
+
# but that is rescued separately in the limits_change_callback
|
|
118
|
+
packet.check_limits(System.limits_set)
|
|
107
119
|
|
|
120
|
+
# This is what updates the CVT
|
|
108
121
|
TelemetryDecomTopic.write_packet(packet, scope: @scope)
|
|
109
122
|
diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
|
|
110
123
|
@metric.set(name: 'decom_duration_seconds', value: diff, type: 'gauge', unit: 'seconds')
|
|
@@ -150,12 +163,14 @@ module OpenC3
|
|
|
150
163
|
|
|
151
164
|
if item.limits.response
|
|
152
165
|
begin
|
|
166
|
+
# TODO: The limits response is user code and should be run as a separate thread / process
|
|
167
|
+
# If this code blocks it will delay TelemetryDecomTopic.write_packet
|
|
153
168
|
item.limits.response.call(packet, item, old_limits_state)
|
|
154
169
|
rescue Exception => e
|
|
155
170
|
@error = e
|
|
156
171
|
@logger.error "#{packet.target_name} #{packet.packet_name} #{item.name} Limits Response Exception!"
|
|
157
172
|
@logger.error "Called with old_state = #{old_limits_state}, new_state = #{item.limits.state}"
|
|
158
|
-
@logger.error e.
|
|
173
|
+
@logger.error e.filtered
|
|
159
174
|
end
|
|
160
175
|
end
|
|
161
176
|
end
|
|
@@ -31,6 +31,7 @@ require 'openc3/topics/command_topic'
|
|
|
31
31
|
require 'openc3/topics/command_decom_topic'
|
|
32
32
|
require 'openc3/topics/interface_topic'
|
|
33
33
|
require 'openc3/topics/router_topic'
|
|
34
|
+
require 'openc3/interfaces/interface'
|
|
34
35
|
|
|
35
36
|
module OpenC3
|
|
36
37
|
class InterfaceCmdHandlerThread
|
|
@@ -191,22 +192,59 @@ module OpenC3
|
|
|
191
192
|
next e.message
|
|
192
193
|
end
|
|
193
194
|
|
|
195
|
+
command.extra ||= {}
|
|
196
|
+
command.extra['cmd_string'] = msg_hash['cmd_string']
|
|
197
|
+
command.extra['username'] = msg_hash['username']
|
|
194
198
|
if hazardous_check
|
|
195
199
|
hazardous, hazardous_description = System.commands.cmd_pkt_hazardous?(command)
|
|
196
200
|
# Return back the error, description, and the formatted command
|
|
197
201
|
# This allows the error handler to simply re-send the command
|
|
198
|
-
next "HazardousError\n#{hazardous_description}\n#{
|
|
202
|
+
next "HazardousError\n#{hazardous_description}\n#{msg_hash['cmd_string']}" if hazardous
|
|
199
203
|
end
|
|
200
204
|
|
|
205
|
+
validate = ConfigParser.handle_true_false(msg_hash['validate'])
|
|
201
206
|
begin
|
|
202
207
|
if @interface.connected?
|
|
208
|
+
result = true
|
|
209
|
+
reason = nil
|
|
210
|
+
if command.validator and validate
|
|
211
|
+
begin
|
|
212
|
+
result, reason = command.validator.pre_check(command)
|
|
213
|
+
rescue => e
|
|
214
|
+
result = false
|
|
215
|
+
reason = e.message
|
|
216
|
+
end
|
|
217
|
+
# Explicitly check for false to allow nil to represent unknown
|
|
218
|
+
if result == false
|
|
219
|
+
message = "pre_check returned false for #{msg_hash['cmd_string']} due to #{reason}"
|
|
220
|
+
raise WriteRejectError.new(message)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
203
224
|
@count += 1
|
|
204
225
|
@metric.set(name: 'interface_cmd_total', value: @count, type: 'counter') if @metric
|
|
205
|
-
|
|
206
226
|
@interface.write(command)
|
|
207
|
-
|
|
227
|
+
|
|
228
|
+
if command.validator and validate
|
|
229
|
+
begin
|
|
230
|
+
result, reason = command.validator.post_check(command)
|
|
231
|
+
rescue => e
|
|
232
|
+
result = false
|
|
233
|
+
reason = e.message
|
|
234
|
+
end
|
|
235
|
+
command.extra['cmd_success'] = result
|
|
236
|
+
command.extra['cmd_reason'] = reason if reason
|
|
237
|
+
end
|
|
238
|
+
|
|
208
239
|
CommandDecomTopic.write_packet(command, scope: @scope)
|
|
240
|
+
CommandTopic.write_packet(command, scope: @scope)
|
|
209
241
|
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
|
242
|
+
|
|
243
|
+
# Explicitly check for false to allow nil to represent unknown
|
|
244
|
+
if result == false
|
|
245
|
+
message = "post_check returned false for #{msg_hash['cmd_string']} due to #{reason}"
|
|
246
|
+
raise WriteRejectError.new(message)
|
|
247
|
+
end
|
|
210
248
|
next 'SUCCESS'
|
|
211
249
|
else
|
|
212
250
|
next "Interface not connected: #{@interface.name}"
|
|
@@ -368,7 +368,7 @@ module OpenC3
|
|
|
368
368
|
end
|
|
369
369
|
|
|
370
370
|
# The reaction snooze manager starts a thread pool and keeps track of when a
|
|
371
|
-
# reaction is activated and to
|
|
371
|
+
# reaction is activated and to evaluate triggers when the snooze is complete.
|
|
372
372
|
class ReactionSnoozeManager
|
|
373
373
|
attr_reader :name, :scope, :share, :thread_pool
|
|
374
374
|
|
|
@@ -432,7 +432,7 @@ module OpenC3
|
|
|
432
432
|
|
|
433
433
|
def shutdown
|
|
434
434
|
@cancel_thread = true
|
|
435
|
-
@worker_count.times do |
|
|
435
|
+
@worker_count.times do |_i|
|
|
436
436
|
@share.queue_base.enqueue(kind: nil, data: nil)
|
|
437
437
|
end
|
|
438
438
|
end
|
|
@@ -445,7 +445,7 @@ module OpenC3
|
|
|
445
445
|
visited["#{trigger.name}__P"] = Hash.new
|
|
446
446
|
end
|
|
447
447
|
if visited["#{head.name}__P"][trigger.name]
|
|
448
|
-
# Not sure if this is
|
|
448
|
+
# Not sure if this is possible as on create it validates that the dependents are already created
|
|
449
449
|
message = "loop detected from #{head.name} -> #{trigger.name} path: #{visited["#{head.name}__P"]}"
|
|
450
450
|
notify(name: trigger.name, severity: 'error', message: message)
|
|
451
451
|
return visited["#{trigger.name}__R"] = -1
|
|
@@ -494,7 +494,7 @@ module OpenC3
|
|
|
494
494
|
end
|
|
495
495
|
|
|
496
496
|
# The trigger manager starts a thread pool and subscribes
|
|
497
|
-
# to the
|
|
497
|
+
# to the telemetry decom topic. It adds the "packet" to the thread pool queue
|
|
498
498
|
# and the thread will evaluate the "trigger".
|
|
499
499
|
class TriggerGroupManager
|
|
500
500
|
attr_reader :name, :scope, :share, :group, :topics, :thread_pool
|
|
@@ -621,7 +621,7 @@ module OpenC3
|
|
|
621
621
|
loop do
|
|
622
622
|
triggers = TriggerModel.all(scope: @scope, group: @group)
|
|
623
623
|
@share.trigger_base.rebuild(triggers: triggers)
|
|
624
|
-
@manager.refresh() #
|
|
624
|
+
@manager.refresh() # Every time we do a full base update we refresh the manager
|
|
625
625
|
break if @cancel_thread
|
|
626
626
|
block_for_updates()
|
|
627
627
|
break if @cancel_thread
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'openc3/utilities/migration'
|
|
2
|
+
require 'openc3/models/scope_model'
|
|
3
|
+
require 'openc3/models/timeline_model'
|
|
4
|
+
|
|
5
|
+
module OpenC3
|
|
6
|
+
class ActivityUuid < Migration
|
|
7
|
+
def self.run
|
|
8
|
+
ScopeModel.names.each do |scope|
|
|
9
|
+
TimelineModel.names.each do |key|
|
|
10
|
+
name = key.split('__').last
|
|
11
|
+
json = Store.zrange("#{scope}#{ActivityModel::PRIMARY_KEY}__#{name}", 0, -1)
|
|
12
|
+
parsed = json.map { |value| JSON.parse(value, :allow_nan => true, :create_additions => true) }
|
|
13
|
+
parsed.each_with_index do |activity, index|
|
|
14
|
+
if activity['uuid'].nil?
|
|
15
|
+
activity['uuid'] = SecureRandom.uuid
|
|
16
|
+
Store.zrem("#{scope}#{ActivityModel::PRIMARY_KEY}__#{name}", json[index])
|
|
17
|
+
Store.zadd("#{scope}#{ActivityModel::PRIMARY_KEY}__#{name}", activity['start'], JSON.generate(activity))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
unless ENV['OPENC3_NO_MIGRATE']
|
|
27
|
+
OpenC3::ActivityUuid.run
|
|
28
|
+
end
|