openc3 6.9.2 → 6.10.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/data/config/command_modifiers.yaml +79 -0
  3. data/data/config/item_modifiers.yaml +5 -0
  4. data/data/config/parameter_modifiers.yaml +5 -0
  5. data/data/config/telemetry_modifiers.yaml +79 -0
  6. data/ext/openc3/ext/packet/packet.c +9 -0
  7. data/lib/openc3/accessors/accessor.rb +27 -3
  8. data/lib/openc3/accessors/binary_accessor.rb +21 -4
  9. data/lib/openc3/accessors/template_accessor.rb +3 -2
  10. data/lib/openc3/api/cmd_api.rb +7 -3
  11. data/lib/openc3/api/tlm_api.rb +17 -7
  12. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +19 -13
  13. data/lib/openc3/io/json_rpc.rb +6 -0
  14. data/lib/openc3/microservices/decom_microservice.rb +97 -17
  15. data/lib/openc3/microservices/interface_decom_common.rb +32 -0
  16. data/lib/openc3/microservices/interface_microservice.rb +3 -75
  17. data/lib/openc3/microservices/queue_microservice.rb +16 -1
  18. data/lib/openc3/migrations/20251022000000_remove_unique_id.rb +23 -0
  19. data/lib/openc3/models/plugin_model.rb +7 -1
  20. data/lib/openc3/models/queue_model.rb +32 -5
  21. data/lib/openc3/models/reaction_model.rb +25 -9
  22. data/lib/openc3/models/target_model.rb +78 -10
  23. data/lib/openc3/packets/commands.rb +33 -7
  24. data/lib/openc3/packets/packet.rb +75 -71
  25. data/lib/openc3/packets/packet_config.rb +78 -29
  26. data/lib/openc3/packets/packet_item.rb +11 -103
  27. data/lib/openc3/packets/parsers/packet_item_parser.rb +177 -34
  28. data/lib/openc3/packets/parsers/xtce_converter.rb +2 -2
  29. data/lib/openc3/packets/structure.rb +29 -21
  30. data/lib/openc3/packets/structure_item.rb +31 -19
  31. data/lib/openc3/packets/telemetry.rb +37 -11
  32. data/lib/openc3/script/suite_results.rb +2 -2
  33. data/lib/openc3/subpacketizers/subpacketizer.rb +18 -0
  34. data/lib/openc3/system/target.rb +3 -32
  35. data/lib/openc3/tools/table_manager/table_config.rb +9 -1
  36. data/lib/openc3/tools/table_manager/table_item_parser.rb +2 -2
  37. data/lib/openc3/top_level.rb +45 -19
  38. data/lib/openc3/topics/decom_interface_topic.rb +31 -0
  39. data/lib/openc3/utilities/env_helper.rb +10 -0
  40. data/lib/openc3/utilities/logger.rb +7 -11
  41. data/lib/openc3/version.rb +6 -6
  42. data/tasks/spec.rake +2 -1
  43. data/templates/tool_angular/package.json +2 -2
  44. data/templates/tool_react/package.json +1 -1
  45. data/templates/tool_svelte/package.json +1 -1
  46. data/templates/tool_vue/package.json +3 -3
  47. data/templates/widget/package.json +2 -2
  48. metadata +4 -1
@@ -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 2024, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -68,12 +68,6 @@ module OpenC3
68
68
  # @return [Integer] The number of telemetry packets received from this target
69
69
  attr_accessor :tlm_cnt
70
70
 
71
- # @return [Boolean] Indicates if all command packets identify using different fields
72
- attr_accessor :cmd_unique_id_mode
73
-
74
- # @return [Boolean] Indicates if telemetry packets identify using different fields
75
- attr_accessor :tlm_unique_id_mode
76
-
77
71
  # @return [String] Id of the target configuration
78
72
  attr_accessor :id
79
73
 
@@ -91,13 +85,10 @@ module OpenC3
91
85
  @ignored_parameters = []
92
86
  @ignored_items = []
93
87
  @cmd_tlm_files = []
94
- # @auto_screen_substitute = false
95
88
  @interface = nil
96
89
  @routers = []
97
90
  @cmd_cnt = 0
98
91
  @tlm_cnt = 0
99
- @cmd_unique_id_mode = false
100
- @tlm_unique_id_mode = false
101
92
  @name = target_name.clone.upcase.freeze
102
93
  get_target_dir(path, gem_path)
103
94
  process_target_config_file()
@@ -174,20 +165,8 @@ module OpenC3
174
165
 
175
166
  @cmd_tlm_files << filename
176
167
 
177
- # when 'AUTO_SCREEN_SUBSTITUTE'
178
- # usage = "#{keyword}"
179
- # parser.verify_num_parameters(0, 0, usage)
180
- # @auto_screen_substitute = true
181
-
182
- when 'CMD_UNIQUE_ID_MODE'
183
- usage = "#{keyword}"
184
- parser.verify_num_parameters(0, 0, usage)
185
- @cmd_unique_id_mode = true
186
-
187
- when 'TLM_UNIQUE_ID_MODE'
188
- usage = "#{keyword}"
189
- parser.verify_num_parameters(0, 0, usage)
190
- @tlm_unique_id_mode = true
168
+ when 'CMD_UNIQUE_ID_MODE', 'TLM_UNIQUE_ID_MODE'
169
+ # Deprecated - Now autodetected
191
170
 
192
171
  else
193
172
  # blank lines will have a nil keyword and should not raise an exception
@@ -202,15 +181,7 @@ module OpenC3
202
181
  config['requires'] = @requires
203
182
  config['ignored_parameters'] = @ignored_parameters
204
183
  config['ignored_items'] = @ignored_items
205
- # config['auto_screen_substitute'] = true if @auto_screen_substitute
206
184
  config['cmd_tlm_files'] = @cmd_tlm_files
207
- # config['filename'] = @filename
208
- # config['interface'] = @interface.name if @interface
209
- # config['dir'] = @dir
210
- # config['cmd_cnt'] = @cmd_cnt
211
- # config['tlm_cnt'] = @tlm_cnt
212
- config['cmd_unique_id_mode'] = true if @cmd_unique_id_mode
213
- config['tlm_unique_id_mode'] = true if @tlm_unique_id_mode
214
185
  config['id'] = @id
215
186
  config
216
187
  end
@@ -226,7 +226,7 @@ module OpenC3
226
226
  # (see PacketConfig#start_item)
227
227
  def start_item(parser)
228
228
  finish_item
229
- @current_item = TableItemParser.parse(parser, @current_packet, @warnings)
229
+ @current_item = TableItemParser.parse(parser, self, @current_packet, @warnings)
230
230
  end
231
231
 
232
232
  # If the table is ROW_COLUMN all currently defined items are
@@ -266,6 +266,14 @@ module OpenC3
266
266
  item.default = @defaults[index].to_f
267
267
  when :STRING, :BLOCK
268
268
  item.default = @defaults[index]
269
+ when :BOOL
270
+ item.default = ConfigParser.handle_true_false(@defaults[index])
271
+ when :ARRAY, :OBJECT, :ANY
272
+ begin
273
+ item.default = JSON.parse(@defaults[index], allow_nan: true)
274
+ rescue Exception
275
+ item.default = @defaults[index]
276
+ end
269
277
  end
270
278
  end
271
279
  end
@@ -30,8 +30,8 @@ module OpenC3
30
30
  # @param parser [ConfigParser] Configuration parser
31
31
  # @param table [Table] Table all parsed items should be added to
32
32
  # # @param warnings [Array<String>] Array of warning strings from PacketConfig
33
- def self.parse(parser, table, warnings)
34
- parser = TableItemParser.new(parser, warnings)
33
+ def self.parse(parser, table_config, table, warnings)
34
+ parser = TableItemParser.new(parser, table_config, warnings)
35
35
  parser.verify_parameters(PacketConfig::COMMAND)
36
36
  parser.create_table_item(table)
37
37
  end
@@ -26,7 +26,6 @@ require 'digest'
26
26
  require 'open3'
27
27
  require 'openc3/core_ext'
28
28
  require 'openc3/version'
29
- require 'openc3/utilities/logger'
30
29
  require 'socket'
31
30
  require 'pathname'
32
31
 
@@ -107,6 +106,8 @@ module OpenC3
107
106
  end
108
107
  end
109
108
 
109
+ require 'openc3/utilities/logger'
110
+
110
111
  # Creates a marshal file by serializing the given obj
111
112
  #
112
113
  # @param marshal_filename [String] Name of the marshal file to create
@@ -551,30 +552,55 @@ module OpenC3
551
552
  end
552
553
  end
553
554
 
554
- # The following code makes most older COSMOS 5 plugins still work with OpenC3
555
+ # The following code makes most older COSMOS plugins still work with OpenC3
555
556
  # New plugins should only use openc3 paths and module OpenC3
556
557
  unless ENV['OPENC3_NO_COSMOS_COMPATIBILITY']
557
558
  Cosmos = OpenC3
558
559
  ENV['COSMOS_SCOPE'] = ENV['OPENC3_SCOPE']
559
- module CosmosCompatibility
560
- def require(*args)
561
- filename = args[0]
562
- if filename[0..6] == "cosmos/"
563
- filename[0..6] = "openc3/"
560
+
561
+ # Don't apply the compatibility layer in test environments to avoid conflicts with RSpec
562
+ unless defined?(RSpec) || ENV['RAILS_ENV'] == 'test' || ENV['RACK_ENV'] == 'test'
563
+ module CosmosCompatibility
564
+ # Validates the filename after cosmos->openc3 transformation
565
+ def safe_openc3_path?(filename)
566
+ return false unless filename.is_a?(String)
567
+ # Only validate paths that start with "openc3/" (transformed from "cosmos/")
568
+ return true unless filename.start_with?("openc3/")
569
+ # Disallow any ".." or "." path traversal
570
+ return false if filename.include?("..") || filename.include?("./") || filename.include?("/.") || filename.include?("\\") || filename.include?("//")
571
+ # Disallow absolute paths (Unix and Windows)
572
+ return false if filename.start_with?("/") || filename =~ /^[a-zA-Z]:[\\\/]/
573
+ # Disallow special characters (allow word chars, dash, slash, dot)
574
+ return false unless filename =~ /\A[\w\-\/\.]+\z/
575
+ true
564
576
  end
565
- args[0] = filename
566
- super(*args)
567
- end
568
- def load(*args)
569
- filename = args[0]
570
- if filename[0..6] == "cosmos/"
571
- filename[0..6] = "openc3/"
577
+
578
+ def require(*args)
579
+ filename = args[0]
580
+ if filename.is_a?(String) && filename.start_with?("cosmos/")
581
+ filename = filename.sub(/^cosmos\//, "openc3/")
582
+ unless safe_openc3_path?(filename)
583
+ raise ArgumentError, "Unsafe path in require after cosmos->openc3 transformation: #{filename.inspect}"
584
+ end
585
+ args[0] = filename
586
+ end
587
+ super(*args)
588
+ end
589
+
590
+ def load(*args)
591
+ filename = args[0]
592
+ if filename.is_a?(String) && filename.start_with?("cosmos/")
593
+ filename = filename.sub(/^cosmos\//, "openc3/")
594
+ unless safe_openc3_path?(filename)
595
+ raise ArgumentError, "Unsafe path in load after cosmos->openc3 transformation: #{filename.inspect}"
596
+ end
597
+ args[0] = filename
598
+ end
599
+ super(*args)
572
600
  end
573
- args[0] = filename
574
- super(*args)
575
601
  end
576
- end
577
- class Object
578
- include CosmosCompatibility
602
+ class Object
603
+ include CosmosCompatibility
604
+ end
579
605
  end
580
606
  end
@@ -17,6 +17,7 @@
17
17
  # if purchased from OpenC3, Inc.
18
18
 
19
19
  require 'openc3/topics/topic'
20
+ require 'openc3/config/config_parser'
20
21
 
21
22
  module OpenC3
22
23
  class DecomInterfaceTopic < Topic
@@ -58,5 +59,35 @@ module OpenC3
58
59
  Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
59
60
  { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
60
61
  end
62
+
63
+ def self.get_tlm_buffer(target_name, packet_name, timeout: 5, scope:)
64
+ data = {}
65
+ data['target_name'] = target_name.to_s.upcase
66
+ data['packet_name'] = packet_name.to_s.upcase
67
+ # DecomMicroservice is listening to the DECOMINTERFACE topic and has
68
+ # the most recent decommed packets including subpackets
69
+ ack_topic = "{#{scope}__ACKCMD}TARGET__#{target_name}"
70
+ Topic.update_topic_offsets([ack_topic])
71
+ decom_id = Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
72
+ { 'get_tlm_buffer' => JSON.generate(data, allow_nan: true) }, '*', 100)
73
+ time = Time.now
74
+ while (Time.now - time) < timeout
75
+ Topic.read_topics([ack_topic]) do |_topic, _msg_id, msg_hash, _redis|
76
+ if msg_hash["id"] == decom_id
77
+ if msg_hash["result"] == "SUCCESS"
78
+ msg_hash["stored"] = ConfigParser.handle_true_false(msg_hash["stored"])
79
+ extra = msg_hash["extra"]
80
+ if extra and extra.length > 0
81
+ msg_hash["extra"] = JSON.parse(extra, allow_nan: true, create_additions: true)
82
+ end
83
+ return msg_hash
84
+ else
85
+ raise msg_hash["message"]
86
+ end
87
+ end
88
+ end
89
+ end
90
+ raise "Timeout of #{timeout}s waiting for ack. Does target '#{target_name}' exist?"
91
+ end
61
92
  end
62
93
  end
@@ -0,0 +1,10 @@
1
+ # For simple boolean flags
2
+ class EnvHelper
3
+ def self.enabled?(key)
4
+ ['true', '1', 'yes', 'on'].include?(ENV[key].to_s.downcase)
5
+ end
6
+
7
+ def self.set?(key)
8
+ !ENV[key].to_s.empty?
9
+ end
10
+ end
@@ -27,6 +27,7 @@ require 'socket'
27
27
  require 'logger'
28
28
  require 'time'
29
29
  require 'json'
30
+ require 'openc3/utilities/env_helper'
30
31
 
31
32
  module OpenC3
32
33
  # Supports different levels of logging and only writes if the level
@@ -201,19 +202,14 @@ module OpenC3
201
202
  @@mutex.synchronize do
202
203
  data = build_log_data(log_level, message, user: user, type: type, url: url, other: other, &block)
203
204
  if @stdout
204
- case log_level
205
- when WARN_LEVEL, ERROR_LEVEL, FATAL_LEVEL
206
- if ENV['OPENC3_LOG_STDERR']
207
- $stderr.puts data.as_json().to_json(allow_nan: true)
208
- $stderr.flush
209
- else
210
- $stdout.puts data.as_json().to_json(allow_nan: true)
211
- $stdout.flush
212
- end
205
+ # send warning, error, and fatal to stderr if OPENC3_LOG_STDERR env var is set to 1 or true
206
+ if [WARN_LEVEL, ERROR_LEVEL, FATAL_LEVEL].include?(log_level) && EnvHelper.enabled?('OPENC3_LOG_STDERR')
207
+ io = $stderr
213
208
  else
214
- $stdout.puts data.as_json().to_json(allow_nan: true)
215
- $stdout.flush
209
+ io = $stdout
216
210
  end
211
+ io.puts data.as_json().to_json(allow_nan: true)
212
+ io.flush
217
213
  end
218
214
  unless @no_store
219
215
  if scope
@@ -1,14 +1,14 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- OPENC3_VERSION = '6.9.2'
3
+ OPENC3_VERSION = '6.10.0'
4
4
  module OpenC3
5
5
  module Version
6
6
  MAJOR = '6'
7
- MINOR = '9'
8
- PATCH = '2'
7
+ MINOR = '10'
8
+ PATCH = '0'
9
9
  OTHER = ''
10
- BUILD = '0b659342611ec28c5dac351032c18442820977a3'
10
+ BUILD = 'cb022b45a50e7f769e2df3522cf6febbe3ed0998'
11
11
  end
12
- VERSION = '6.9.2'
13
- GEM_VERSION = '6.9.2'
12
+ VERSION = '6.10.0'
13
+ GEM_VERSION = '6.10.0'
14
14
  end
data/tasks/spec.rake CHANGED
@@ -25,7 +25,8 @@ begin
25
25
 
26
26
  desc 'Run all specs with basic output'
27
27
  RSpec::Core::RakeTask.new do |t|
28
- t.pattern = ['spec/*_spec.rb']
28
+ # Use ** to recursively find specs in all subdirectories (spec/utilities/, spec/models/, etc.)
29
+ t.pattern = ['spec/**/*_spec.rb']
29
30
  t.rspec_opts = '-f d --warnings'
30
31
  end
31
32
  rescue LoadError
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= tool_name %>",
3
- "version": "6.9.2",
3
+ "version": "6.10.0",
4
4
  "scripts": {
5
5
  "ng": "ng",
6
6
  "start": "ng serve",
@@ -23,7 +23,7 @@
23
23
  "@angular/platform-browser-dynamic": "^18.2.6",
24
24
  "@angular/router": "^18.2.6",
25
25
  "@astrouxds/astro-web-components": "^7.24.0",
26
- "@openc3/js-common": "6.9.2",
26
+ "@openc3/js-common": "6.10.0",
27
27
  "rxjs": "~7.8.0",
28
28
  "single-spa": "^5.9.5",
29
29
  "single-spa-angular": "^9.2.0",
@@ -16,7 +16,7 @@
16
16
  "@emotion/react": "^11.13.3",
17
17
  "@emotion/styled": "^11.11.0",
18
18
  "@mui/material": "^6.1.1",
19
- "@openc3/js-common": "6.9.2",
19
+ "@openc3/js-common": "6.10.0",
20
20
  "react": "^18.2.0",
21
21
  "react-dom": "^18.2.0",
22
22
  "single-spa-react": "^5.1.4"
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@astrouxds/astro-web-components": "^7.24.0",
15
- "@openc3/js-common": "6.9.2",
15
+ "@openc3/js-common": "6.10.0",
16
16
  "@smui/button": "^7.0.0",
17
17
  "@smui/common": "^7.0.0",
18
18
  "@smui/card": "^7.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= tool_name %>",
3
- "version": "6.9.2",
3
+ "version": "6.10.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -11,8 +11,8 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@astrouxds/astro-web-components": "^7.24.0",
14
- "@openc3/js-common": "6.9.2",
15
- "@openc3/vue-common": "6.9.2",
14
+ "@openc3/js-common": "6.10.0",
15
+ "@openc3/vue-common": "6.10.0",
16
16
  "axios": "^1.7.7",
17
17
  "date-fns": "^4.1.0",
18
18
  "lodash": "^4.17.21",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= widget_name %>",
3
- "version": "6.9.2",
3
+ "version": "6.10.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@astrouxds/astro-web-components": "^7.24.0",
11
- "@openc3/vue-common": "6.9.2",
11
+ "@openc3/vue-common": "6.10.0",
12
12
  "vuetify": "^3.7.1"
13
13
  },
14
14
  "devDependencies": {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openc3
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.9.2
4
+ version: 6.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Melton
@@ -1080,6 +1080,7 @@ files:
1080
1080
  - lib/openc3/migrations/20241208080001_no_trigger_group.rb
1081
1081
  - lib/openc3/migrations/20250108060000_news_feed.rb
1082
1082
  - lib/openc3/migrations/20250402000000_periodic_only_default.rb
1083
+ - lib/openc3/migrations/20251022000000_remove_unique_id.rb
1083
1084
  - lib/openc3/models/activity_model.rb
1084
1085
  - lib/openc3/models/auth_model.rb
1085
1086
  - lib/openc3/models/cvt_model.rb
@@ -1179,6 +1180,7 @@ files:
1179
1180
  - lib/openc3/streams/tcpip_client_stream.rb
1180
1181
  - lib/openc3/streams/tcpip_socket_stream.rb
1181
1182
  - lib/openc3/streams/web_socket_client_stream.rb
1183
+ - lib/openc3/subpacketizers/subpacketizer.rb
1182
1184
  - lib/openc3/system.rb
1183
1185
  - lib/openc3/system/system.rb
1184
1186
  - lib/openc3/system/target.rb
@@ -1221,6 +1223,7 @@ files:
1221
1223
  - lib/openc3/utilities/cosmos_rails_formatter.rb
1222
1224
  - lib/openc3/utilities/crc.rb
1223
1225
  - lib/openc3/utilities/csv.rb
1226
+ - lib/openc3/utilities/env_helper.rb
1224
1227
  - lib/openc3/utilities/local_bucket.rb
1225
1228
  - lib/openc3/utilities/local_mode.rb
1226
1229
  - lib/openc3/utilities/logger.rb