cosmos 4.4.0-java → 4.4.1-java
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/.dockerignore +2 -0
- data/.gitignore +1 -0
- data/.travis.yml +6 -6
- data/Dockerfile +65 -0
- data/Manifest.txt +12 -2
- data/README.md +5 -0
- data/Rakefile +52 -0
- data/appveyor.yml +18 -8
- data/autohotkey/config/tools/cmd_sequence/cmd_sequence.txt +2 -0
- data/autohotkey/lib/cmd_sequence_exporter.rb +52 -0
- data/autohotkey/procedures/collect.rb +2 -2
- data/autohotkey/procedures/collect_util.rb +1 -1
- data/autohotkey/procedures/script_test.rb +1 -1
- data/autohotkey/tools/CmdSenderAHK2 +18 -0
- data/autohotkey/tools/cmd_sender.ahk +34 -6
- data/autohotkey/tools/cmd_sender2.ahk +4 -0
- data/autohotkey/tools/cmd_sequence.ahk +21 -8
- data/autohotkey/tools/config_editor.ahk +4 -4
- data/bin/cstol_converter +1 -1
- data/cosmos.gemspec +1 -1
- data/data/config/command_modifiers.yaml +16 -1
- data/data/config/param_item_modifiers.yaml +5 -0
- data/data/config/system.yaml +31 -1
- data/data/config/telemetry_modifiers.yaml +16 -1
- data/data/crc.txt +415 -410
- data/demo/config/dart/Gemfile +1 -6
- data/demo/config/data/crc.txt +244 -243
- data/demo/config/system/system.txt +3 -0
- data/demo/config/system/system2.txt +3 -0
- data/demo/config/system/system_alt_ports.txt +3 -0
- data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +3 -3
- data/demo/config/targets/INST/cmd_tlm/inst_tlm.txt +4 -0
- data/demo/config/targets/INST/cmd_tlm/inst_tlm_override.txt +12 -0
- data/demo/config/targets/INST/lib/sim_inst.rb +2 -2
- data/demo/config/targets/INST/target.txt +1 -0
- data/demo/procedures/cosmos_api_test.rb +8 -8
- data/install/config/dart/Gemfile +2 -7
- data/install/config/data/crc.txt +143 -143
- data/install/config/system/system.txt +3 -0
- data/lib/cosmos/dart/config/boot.rb +1 -1
- data/lib/cosmos/dart/config/database.yml +2 -0
- data/lib/cosmos/dart/lib/dart_common.rb +11 -4
- data/lib/cosmos/dart/lib/dart_constants.rb +15 -0
- data/lib/cosmos/dart/lib/dart_decom_query.rb +5 -6
- data/lib/cosmos/dart/lib/dart_decommutator.rb +66 -56
- data/lib/cosmos/dart/lib/dart_master_query.rb +71 -0
- data/lib/cosmos/dart/lib/dart_reducer_worker_thread.rb +165 -134
- data/lib/cosmos/dart/processes/dart.rb +4 -2
- data/lib/cosmos/dart/processes/dart_decom_server.rb +2 -2
- data/lib/cosmos/dart/processes/dart_ingester.rb +38 -1
- data/lib/cosmos/dart/processes/dart_master.rb +44 -0
- data/lib/cosmos/dart/processes/dart_util.rb +115 -0
- data/lib/cosmos/gui/widgets/dart_meta_frame.rb +21 -2
- data/lib/cosmos/interfaces/protocols/length_protocol.rb +5 -0
- data/lib/cosmos/io/json_drb.rb +3 -3
- data/lib/cosmos/io/posix_serial_driver.rb +1 -1
- data/lib/cosmos/io/win32_serial_driver.rb +23 -2
- data/lib/cosmos/packet_logs/packet_log_reader.rb +2 -2
- data/lib/cosmos/packets/packet.rb +1 -1
- data/lib/cosmos/packets/packet_config.rb +26 -8
- data/lib/cosmos/packets/structure.rb +17 -0
- data/lib/cosmos/packets/structure_item.rb +5 -1
- data/lib/cosmos/packets/telemetry.rb +7 -1
- data/lib/cosmos/system/system.rb +115 -48
- data/lib/cosmos/tools/cmd_sender/cmd_params.rb +360 -0
- data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +23 -319
- data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +14 -17
- data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +43 -331
- data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +16 -11
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +1 -0
- data/lib/cosmos/tools/config_editor/config_editor.rb +33 -2
- data/lib/cosmos/tools/config_editor/config_editor_frame.rb +8 -9
- data/lib/cosmos/tools/config_editor/system_config_dialog.rb +158 -0
- data/lib/cosmos/tools/script_runner/script_runner_frame.rb +2 -2
- data/lib/cosmos/tools/test_runner/test.rb +5 -2
- data/lib/cosmos/tools/test_runner/test_runner.rb +2 -2
- data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +17 -13
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_dart_thread.rb +20 -16
- data/lib/cosmos/tools/tlm_grapher/tlm_grapher.rb +18 -11
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +16 -5
- data/lib/cosmos/utilities/ruby_lex_utils.rb +34 -30
- data/lib/cosmos/version.rb +4 -4
- data/lib/cosmos/win32/excel.rb +23 -17
- data/run_gui_tests.bat +1 -0
- data/spec/core_ext/socket_spec.rb +1 -1
- data/spec/install/yaml_docs_spec.rb +26 -6
- data/spec/interfaces/protocols/length_protocol_spec.rb +39 -0
- data/spec/io/json_drb_spec.rb +14 -0
- data/spec/io/win32_serial_driver_spec.rb +16 -2
- data/spec/packet_logs/packet_log_reader_spec.rb +2 -2
- data/spec/packets/structure_spec.rb +52 -2
- data/spec/packets/telemetry_spec.rb +29 -1
- data/spec/system/system_spec.rb +2 -2
- data/spec/utilities/message_log_spec.rb +6 -3
- data/tasks/gemfile_stats.rake +22 -13
- metadata +15 -5
- data/lib/cosmos/dart/Gemfile +0 -69
|
@@ -303,6 +303,23 @@ module Cosmos
|
|
|
303
303
|
end
|
|
304
304
|
end
|
|
305
305
|
|
|
306
|
+
# @param name [String] Name of the item to delete in the items Hash
|
|
307
|
+
def delete_item(name)
|
|
308
|
+
item = @items[name.upcase]
|
|
309
|
+
raise ArgumentError, "Unknown item: #{name}" unless item
|
|
310
|
+
|
|
311
|
+
# Find the item to delete in the sorted_items array
|
|
312
|
+
item_index = nil
|
|
313
|
+
@sorted_items.each_with_index do |sorted_item, index|
|
|
314
|
+
if sorted_item.name == item.name
|
|
315
|
+
item_index = index
|
|
316
|
+
break
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
@sorted_items.delete_at(item_index)
|
|
320
|
+
@items.delete(name.upcase)
|
|
321
|
+
end
|
|
322
|
+
|
|
306
323
|
# Write a value to the buffer based on the item definition
|
|
307
324
|
#
|
|
308
325
|
# @param item [StructureItem] Instance of StructureItem or one of its subclasses
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
require 'cosmos/ext/packet' if RUBY_ENGINE == 'ruby' and !ENV['COSMOS_NO_EXT']
|
|
12
12
|
|
|
13
13
|
module Cosmos
|
|
14
|
-
|
|
15
14
|
# Maintains knowledge of an item in a Structure. Multiple StructureItems
|
|
16
15
|
# compose a Structure.
|
|
17
16
|
class StructureItem
|
|
@@ -59,6 +58,9 @@ module Cosmos
|
|
|
59
58
|
# @return [Symbol] {BinaryAccessor::OVERFLOW_TYPES}
|
|
60
59
|
attr_reader :overflow
|
|
61
60
|
|
|
61
|
+
# @return [Boolean] Whether this structure item can overlap another item in the same packet
|
|
62
|
+
attr_accessor :overlap
|
|
63
|
+
|
|
62
64
|
# A large buffer size in bits (1 Megabyte)
|
|
63
65
|
LARGE_BUFFER_SIZE_BITS = 1024 * 1024 * 8
|
|
64
66
|
|
|
@@ -73,6 +75,7 @@ module Cosmos
|
|
|
73
75
|
# @param endianness [Symbol] {BinaryAccessor::ENDIANNESS}
|
|
74
76
|
# @param array_size [Integer, nil] Size of the array item in bits. For
|
|
75
77
|
# example, if the bit_size is 8, an array_size of 16 holds two values.
|
|
78
|
+
# @param overflow [Symbol] {BinaryAccessor::OVERFLOW_TYPES}
|
|
76
79
|
def initialize(name, bit_offset, bit_size, data_type, endianness, array_size = nil, overflow = :ERROR)
|
|
77
80
|
@structure_item_constructed = false
|
|
78
81
|
# Assignment order matters due to verifications!
|
|
@@ -83,6 +86,7 @@ module Cosmos
|
|
|
83
86
|
self.bit_size = bit_size
|
|
84
87
|
self.array_size = array_size
|
|
85
88
|
self.overflow = overflow
|
|
89
|
+
self.overlap = false
|
|
86
90
|
@create_index = @@create_index
|
|
87
91
|
@@create_index += 1
|
|
88
92
|
@structure_item_constructed = true
|
|
@@ -437,7 +437,13 @@ module Cosmos
|
|
|
437
437
|
splash.progress = index / total
|
|
438
438
|
end
|
|
439
439
|
|
|
440
|
-
|
|
440
|
+
# Note: System only has declared target structures but telemetry may have more
|
|
441
|
+
system_target = System.targets[target_name]
|
|
442
|
+
if system_target
|
|
443
|
+
ignored_items = system_target.ignored_items
|
|
444
|
+
else
|
|
445
|
+
ignored_items = []
|
|
446
|
+
end
|
|
441
447
|
|
|
442
448
|
packets(target_name).each do |packet_name, packet|
|
|
443
449
|
# We don't audit against hidden or disabled packets
|
data/lib/cosmos/system/system.rb
CHANGED
|
@@ -20,6 +20,7 @@ require 'drb/acl'
|
|
|
20
20
|
require 'zip'
|
|
21
21
|
require 'zip/filesystem'
|
|
22
22
|
require 'bundler'
|
|
23
|
+
require 'thread'
|
|
23
24
|
|
|
24
25
|
module Cosmos
|
|
25
26
|
# System is the primary entry point into the COSMOS framework. It captures
|
|
@@ -77,9 +78,9 @@ module Cosmos
|
|
|
77
78
|
instance_attr_reader :hashing_algorithm
|
|
78
79
|
|
|
79
80
|
# Known COSMOS ports
|
|
80
|
-
KNOWN_PORTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER', 'REPLAY_API', 'REPLAY_PREIDENTIFIED', 'REPLAY_CMD_ROUTER', 'DART_STREAM', 'DART_DECOM']
|
|
81
|
+
KNOWN_PORTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER', 'REPLAY_API', 'REPLAY_PREIDENTIFIED', 'REPLAY_CMD_ROUTER', 'DART_STREAM', 'DART_DECOM', 'DART_MASTER']
|
|
81
82
|
# Known COSMOS hosts
|
|
82
|
-
KNOWN_HOSTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER', 'REPLAY_API', 'REPLAY_PREIDENTIFIED', 'REPLAY_CMD_ROUTER', 'DART_STREAM', 'DART_DECOM']
|
|
83
|
+
KNOWN_HOSTS = ['CTS_API', 'TLMVIEWER_API', 'CTS_PREIDENTIFIED', 'CTS_CMD_ROUTER', 'REPLAY_API', 'REPLAY_PREIDENTIFIED', 'REPLAY_CMD_ROUTER', 'DART_STREAM', 'DART_DECOM', 'DART_MASTER']
|
|
83
84
|
# Known COSMOS paths
|
|
84
85
|
KNOWN_PATHS = ['LOGS', 'TMP', 'SAVED_CONFIG', 'TABLES', 'HANDBOOKS', 'PROCEDURES', 'SEQUENCES', 'DART_DATA', 'DART_LOGS']
|
|
85
86
|
# Supported hashing algorithms
|
|
@@ -195,6 +196,7 @@ module Cosmos
|
|
|
195
196
|
@targets = {}
|
|
196
197
|
# Set config to nil so things will lazy load later
|
|
197
198
|
@config = nil
|
|
199
|
+
@meta_init_filename = nil
|
|
198
200
|
@use_utc = false
|
|
199
201
|
acl_list = []
|
|
200
202
|
all_allowed = false
|
|
@@ -207,7 +209,7 @@ module Cosmos
|
|
|
207
209
|
# First pass - Everything except targets
|
|
208
210
|
parser.parse_file(filename) do |keyword, parameters|
|
|
209
211
|
case keyword
|
|
210
|
-
when 'AUTO_DECLARE_TARGETS', 'DECLARE_TARGET', 'DECLARE_GEM_TARGET'
|
|
212
|
+
when 'AUTO_DECLARE_TARGETS', 'DECLARE_TARGET', 'DECLARE_GEM_TARGET', 'DECLARE_GEM_MULTI_TARGET'
|
|
211
213
|
# Will be handled by second pass
|
|
212
214
|
|
|
213
215
|
when 'PORT'
|
|
@@ -458,6 +460,19 @@ module Cosmos
|
|
|
458
460
|
target = Target.new(target_name, substitute_name, configuration_directory, ConfigParser.handle_nil(parameters[2]), gem_dir)
|
|
459
461
|
@targets[target.name] = target
|
|
460
462
|
|
|
463
|
+
when 'DECLARE_GEM_MULTI_TARGET'
|
|
464
|
+
usage = "#{keyword} <GEM NAME> <TARGET NAME> <SUBSTITUTE TARGET NAME (Optional)> <TARGET FILENAME (Optional - defaults to target.txt)>"
|
|
465
|
+
parser.verify_num_parameters(2, 4, usage)
|
|
466
|
+
|
|
467
|
+
target_name = parameters[1].to_s.upcase
|
|
468
|
+
substitute_name = nil
|
|
469
|
+
substitute_name = ConfigParser.handle_nil(parameters[2])
|
|
470
|
+
substitute_name.to_s.upcase if substitute_name
|
|
471
|
+
gem_dir = Gem::Specification.find_by_name(parameters[0]).gem_dir
|
|
472
|
+
gem_dir = File.join(gem_dir, target_name)
|
|
473
|
+
target = Target.new(target_name, substitute_name, configuration_directory, ConfigParser.handle_nil(parameters[3]), gem_dir)
|
|
474
|
+
@targets[target.name] = target
|
|
475
|
+
|
|
461
476
|
end # case keyword
|
|
462
477
|
end # parser.parse_file
|
|
463
478
|
|
|
@@ -476,48 +491,65 @@ module Cosmos
|
|
|
476
491
|
# configuration. Pass nil to load the default configuration.
|
|
477
492
|
# @return [String, Exception/nil] The actual configuration loaded
|
|
478
493
|
def load_configuration(name = nil)
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
System.commands
|
|
482
|
-
end
|
|
494
|
+
# Ensure packets have been lazy loaded
|
|
495
|
+
load_packets() unless @config
|
|
483
496
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
497
|
+
@@instance_mutex.synchronize do
|
|
498
|
+
if @config_blacklist[name]
|
|
499
|
+
Logger.warn "Ignoring failed config #{name}"
|
|
500
|
+
update_config(@initial_config)
|
|
501
|
+
return @config.name, RuntimeError.new("Ignoring failed config #{name}")
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
if name && @config
|
|
505
|
+
# Make sure they're requesting something other than the current
|
|
506
|
+
# configuration.
|
|
507
|
+
if name != @config.name
|
|
508
|
+
# If they want the initial configuration we can just swap out the
|
|
509
|
+
# current configuration without doing any file processing
|
|
510
|
+
if name == @initial_config.name
|
|
511
|
+
Logger.info "Switching to initial configuration: #{name}"
|
|
512
|
+
update_config(@initial_config)
|
|
513
|
+
else
|
|
514
|
+
# Look for the requested configuration in the saved configurations
|
|
515
|
+
configuration = find_configuration(name)
|
|
516
|
+
if configuration
|
|
517
|
+
# We found the configuration requested. Reprocess the system.txt
|
|
518
|
+
# and reload the packets
|
|
519
|
+
begin
|
|
520
|
+
unless File.directory?(configuration)
|
|
521
|
+
# Zip file configuration so unzip and reset configuration path
|
|
522
|
+
configuration = unzip(configuration)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
Logger.info "Switching to configuration: #{name}"
|
|
526
|
+
process_file(File.join(configuration, 'system.txt'), configuration)
|
|
527
|
+
load_packets(name, false)
|
|
528
|
+
rescue Exception => error
|
|
529
|
+
# Failed to load - Restore initial
|
|
530
|
+
@config_blacklist[name] = true # Prevent wasting time trying to load the bad configuration again
|
|
531
|
+
Logger.error "Problem loading configuration from #{configuration}: #{error.class}:#{error.message}\n#{error.backtrace.join("\n")}\n"
|
|
532
|
+
Logger.info "Switching to initial configuration: #{@initial_config.name}"
|
|
533
|
+
update_config(@initial_config)
|
|
534
|
+
return @config.name, error
|
|
502
535
|
end
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
536
|
+
else
|
|
537
|
+
# We couldn't find the configuration request. Reload the
|
|
538
|
+
# initial configuration
|
|
539
|
+
Logger.error "Unable to find configuration: #{name}"
|
|
540
|
+
Logger.info "Switching to initial configuration: #{@initial_config.name}"
|
|
507
541
|
update_config(@initial_config)
|
|
508
|
-
return @config.name,
|
|
542
|
+
return @config.name, RuntimeError.new("Unable to find configuration: #{name}")
|
|
509
543
|
end
|
|
510
|
-
else
|
|
511
|
-
# We couldn't find the configuration request. Reload the
|
|
512
|
-
# initial configuration
|
|
513
|
-
update_config(@initial_config)
|
|
514
544
|
end
|
|
515
545
|
end
|
|
546
|
+
else
|
|
547
|
+
Logger.info "Switching to initial configuration: #{@initial_config.name}"
|
|
548
|
+
update_config(@initial_config)
|
|
516
549
|
end
|
|
517
|
-
|
|
518
|
-
|
|
550
|
+
|
|
551
|
+
return @config.name, nil
|
|
519
552
|
end
|
|
520
|
-
return @config.name, nil
|
|
521
553
|
end
|
|
522
554
|
|
|
523
555
|
# (see #load_configuration)
|
|
@@ -530,7 +562,6 @@ module Cosmos
|
|
|
530
562
|
# @param filename [String] Path to system.txt config file to process. Defaults to config/system/system.txt
|
|
531
563
|
def reset_variables(filename = nil)
|
|
532
564
|
@targets = {}
|
|
533
|
-
@targets['UNKNOWN'] = Target.new('UNKNOWN')
|
|
534
565
|
@config = nil
|
|
535
566
|
@commands = nil
|
|
536
567
|
@telemetry = nil
|
|
@@ -557,8 +588,10 @@ module Cosmos
|
|
|
557
588
|
@ports['REPLAY_API'] = 7877
|
|
558
589
|
@ports['REPLAY_PREIDENTIFIED'] = 7879
|
|
559
590
|
@ports['REPLAY_CMD_ROUTER'] = 7880
|
|
560
|
-
|
|
561
|
-
@ports['DART_STREAM'] =
|
|
591
|
+
|
|
592
|
+
@ports['DART_STREAM'] = 8777
|
|
593
|
+
@ports['DART_DECOM'] = 8779
|
|
594
|
+
@ports['DART_MASTER'] = 8780
|
|
562
595
|
|
|
563
596
|
@listen_hosts = {}
|
|
564
597
|
@listen_hosts['CTS_API'] = '127.0.0.1'
|
|
@@ -572,6 +605,7 @@ module Cosmos
|
|
|
572
605
|
@listen_hosts['REPLAY_CMD_ROUTER'] = '0.0.0.0'
|
|
573
606
|
@listen_hosts['DART_STREAM'] = '0.0.0.0'
|
|
574
607
|
@listen_hosts['DART_DECOM'] = '0.0.0.0'
|
|
608
|
+
@listen_hosts['DART_MASTER'] = '0.0.0.0'
|
|
575
609
|
|
|
576
610
|
@connect_hosts = {}
|
|
577
611
|
@connect_hosts['CTS_API'] = '127.0.0.1'
|
|
@@ -583,6 +617,7 @@ module Cosmos
|
|
|
583
617
|
@connect_hosts['REPLAY_CMD_ROUTER'] = '127.0.0.1'
|
|
584
618
|
@connect_hosts['DART_STREAM'] = '127.0.0.1'
|
|
585
619
|
@connect_hosts['DART_DECOM'] = '127.0.0.1'
|
|
620
|
+
@connect_hosts['DART_MASTER'] = '127.0.0.1'
|
|
586
621
|
|
|
587
622
|
@paths = {}
|
|
588
623
|
@paths['LOGS'] = File.join(USERPATH, 'outputs', 'logs')
|
|
@@ -611,6 +646,7 @@ module Cosmos
|
|
|
611
646
|
|
|
612
647
|
@initial_filename = filename
|
|
613
648
|
@initial_config = nil
|
|
649
|
+
@config_blacklist = {}
|
|
614
650
|
end
|
|
615
651
|
|
|
616
652
|
# Reset variables and load packets
|
|
@@ -689,11 +725,31 @@ module Cosmos
|
|
|
689
725
|
Bundler.load.specs.each do |spec|
|
|
690
726
|
spec_name_split = spec.name.split('-')
|
|
691
727
|
if spec_name_split.length > 1 && (spec_name_split[0] == 'cosmos')
|
|
692
|
-
#
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
728
|
+
# search for multiple targets packaged in a single gem
|
|
729
|
+
dirs = []
|
|
730
|
+
Dir.foreach(spec.gem_dir) { |dir_filename| dirs << dir_filename }
|
|
731
|
+
dirs.sort!
|
|
732
|
+
dirs.each do |dir_filename|
|
|
733
|
+
if dir_filename == "."
|
|
734
|
+
# check the base directory
|
|
735
|
+
curr_dir = spec.gem_dir
|
|
736
|
+
target_name = spec_name_split[1..-1].join('-').to_s.upcase
|
|
737
|
+
else
|
|
738
|
+
#check for targets in other directories 1 level deep
|
|
739
|
+
next if dir_filename[0] == '.' #skip dot directories and ".."
|
|
740
|
+
next if dir_filename != dir_filename.upcase #skip non uppercase directories
|
|
741
|
+
curr_dir = File.join(spec.gem_dir, dir_filename)
|
|
742
|
+
target_name = dir_filename
|
|
743
|
+
end
|
|
744
|
+
# check for the cmd_tlm directory - if it has it, then we have found a target
|
|
745
|
+
if File.directory?(File.join(curr_dir,'cmd_tlm'))
|
|
746
|
+
# If any of the targets original directory name matches the
|
|
747
|
+
# current directory then it must have been already processed by
|
|
748
|
+
# DECLARE_TARGET so we skip it.
|
|
749
|
+
next if @targets.select {|name, target| target.original_name == target_name }.length > 0
|
|
750
|
+
target = Target.new(target_name,nil, nil, nil, spec.gem_dir)
|
|
751
|
+
@targets[target.name] = target
|
|
752
|
+
end
|
|
697
753
|
end
|
|
698
754
|
end
|
|
699
755
|
end
|
|
@@ -722,9 +778,10 @@ module Cosmos
|
|
|
722
778
|
configuration = find_configuration(@config.name)
|
|
723
779
|
configuration = File.join(@paths['SAVED_CONFIG'], File.build_timestamped_filename([@config.name], '.zip')) unless configuration
|
|
724
780
|
unless File.exist?(configuration)
|
|
781
|
+
configuration_tmp = File.join(@paths['SAVED_CONFIG'], File.build_timestamped_filename(['tmp_' + @config.name], '.zip.tmp'))
|
|
725
782
|
begin
|
|
726
783
|
Zip.continue_on_exists_proc = true
|
|
727
|
-
Zip::File.open(
|
|
784
|
+
Zip::File.open(configuration_tmp, Zip::File::CREATE) do |zipfile|
|
|
728
785
|
zip_file_path = File.basename(configuration, ".zip")
|
|
729
786
|
zipfile.mkdir zip_file_path
|
|
730
787
|
|
|
@@ -756,6 +813,7 @@ module Cosmos
|
|
|
756
813
|
end
|
|
757
814
|
end
|
|
758
815
|
end
|
|
816
|
+
File.rename(configuration_tmp, configuration)
|
|
759
817
|
File.chmod(0444, configuration) # Mark readonly
|
|
760
818
|
rescue Exception => error
|
|
761
819
|
Logger.error "Problem saving configuration to #{configuration}: #{error.class}:#{error.message}\n#{error.backtrace.join("\n")}\n"
|
|
@@ -764,7 +822,7 @@ module Cosmos
|
|
|
764
822
|
end
|
|
765
823
|
end
|
|
766
824
|
|
|
767
|
-
def
|
|
825
|
+
def load_packets_internal(configuration_name = nil)
|
|
768
826
|
# Determine hashing over all targets cmd_tlm files
|
|
769
827
|
cmd_tlm_files = []
|
|
770
828
|
additional_data = ''
|
|
@@ -785,7 +843,6 @@ module Cosmos
|
|
|
785
843
|
# Only use at most, 32 characters of the hex
|
|
786
844
|
hash_string = hash_string[-32..-1] if hash_string.length >= 32
|
|
787
845
|
|
|
788
|
-
|
|
789
846
|
# Build filename for marshal file
|
|
790
847
|
marshal_filename = File.join(@paths['TMP'], 'marshal_' << hash_string << '.bin')
|
|
791
848
|
|
|
@@ -831,6 +888,16 @@ module Cosmos
|
|
|
831
888
|
save_configuration()
|
|
832
889
|
end
|
|
833
890
|
|
|
891
|
+
def load_packets(configuration_name = nil, take_mutex = true)
|
|
892
|
+
if take_mutex
|
|
893
|
+
@@instance_mutex.synchronize do
|
|
894
|
+
load_packets_internal(configuration_name)
|
|
895
|
+
end
|
|
896
|
+
else
|
|
897
|
+
load_packets_internal(configuration_name)
|
|
898
|
+
end
|
|
899
|
+
end
|
|
900
|
+
|
|
834
901
|
def setup_system_meta
|
|
835
902
|
# Ensure SYSTEM META is defined and defined correctly
|
|
836
903
|
begin
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2014 Ball Aerospace & Technologies Corp.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
|
7
|
+
# under the terms of the GNU General Public License
|
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
|
10
|
+
|
|
11
|
+
require 'cosmos'
|
|
12
|
+
Cosmos.catch_fatal_exception do
|
|
13
|
+
require 'cosmos/tools/cmd_sender/cmd_param_table_item_delegate'
|
|
14
|
+
require 'cosmos/gui/dialogs/cmd_details_dialog'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module Cosmos
|
|
18
|
+
# Builds a command parameter widget for use in Command Sender and Command Sequence.
|
|
19
|
+
# The main method is update_cmd_params which builds all the widgets. It can take
|
|
20
|
+
# existing values for use in populating the command parameter widgets.
|
|
21
|
+
class CmdParams < Qt::Widget
|
|
22
|
+
# Class instance variables which apply to all command parameters
|
|
23
|
+
@states_in_hex = false
|
|
24
|
+
@show_ignored = false
|
|
25
|
+
class << self
|
|
26
|
+
attr_accessor :states_in_hex, :show_ignored
|
|
27
|
+
end
|
|
28
|
+
MANUALLY = CmdParamTableItemDelegate::MANUALLY
|
|
29
|
+
# Emit the modified signal to allow changes to propagate upwards
|
|
30
|
+
signals 'modified()'
|
|
31
|
+
|
|
32
|
+
def initialize
|
|
33
|
+
super()
|
|
34
|
+
@param_widgets = []
|
|
35
|
+
@table = nil
|
|
36
|
+
@packet = nil
|
|
37
|
+
@file_dir = System.paths['LOGS']
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Changes the display of items with states to hex if checked is true.
|
|
41
|
+
# Otherwise state values are displayed as decimal.
|
|
42
|
+
# @param checked [Boolean] Whether to display state values in hex
|
|
43
|
+
def states_in_hex(checked)
|
|
44
|
+
CmdParams.states_in_hex = checked
|
|
45
|
+
@param_widgets.each do |_, _, state_value_item|
|
|
46
|
+
next unless state_value_item
|
|
47
|
+
text = state_value_item.text
|
|
48
|
+
quotes_removed = text.remove_quotes
|
|
49
|
+
if text == quotes_removed
|
|
50
|
+
if checked
|
|
51
|
+
if text.is_int?
|
|
52
|
+
@table.blockSignals(true)
|
|
53
|
+
state_value_item.text = sprintf("0x%X", text.to_i)
|
|
54
|
+
@table.blockSignals(false)
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
if text.is_hex?
|
|
58
|
+
@table.blockSignals(true)
|
|
59
|
+
state_value_item.text = Integer(text).to_s
|
|
60
|
+
@table.blockSignals(false)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [Hash] Hash keyed by parameter name with String formatted value
|
|
68
|
+
def params_text(raw = false)
|
|
69
|
+
params = {}
|
|
70
|
+
Qt.execute_in_main_thread do
|
|
71
|
+
@param_widgets.each do |packet_item, value_item, state_value_item|
|
|
72
|
+
text = value_item.text
|
|
73
|
+
text = state_value_item.text if state_value_item && (text == MANUALLY or raw)
|
|
74
|
+
quotes_removed = text.remove_quotes
|
|
75
|
+
if text == quotes_removed
|
|
76
|
+
if (packet_item.data_type == :STRING or packet_item.data_type == :BLOCK) and text.upcase.start_with?("0X")
|
|
77
|
+
params[packet_item.name] = text.hex_to_byte_string
|
|
78
|
+
else
|
|
79
|
+
params[packet_item.name] = text.convert_to_value
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
params[packet_item.name] = quotes_removed
|
|
83
|
+
end
|
|
84
|
+
Kernel.raise "#{packet_item.name} is required." if quotes_removed == '' && packet_item.required
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
params
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Primary method which builds the command parameter table. The passed in command packet
|
|
91
|
+
# is used to get all the command parameters to build. Existing parameters can be passed
|
|
92
|
+
# in to set the initial values for all command parameters. You can also specify whether
|
|
93
|
+
# to display the ignored parameters when building the command parameter table. Note that
|
|
94
|
+
# each time this method is called the TableWidget is disposed and rebuilt.
|
|
95
|
+
#
|
|
96
|
+
# @param packet [Packet] The command packet to build a parameter list for
|
|
97
|
+
# @param existing [Hash] Hash keyed by parameter name with text values.
|
|
98
|
+
# These values will be used as the defaults for all command parameters.
|
|
99
|
+
# @param show_ignored [Boolean] Whether to display the ignored
|
|
100
|
+
# parameters. Pass nil (the default) to keep the existing setting.
|
|
101
|
+
def update_cmd_params(packet, existing: nil, show_ignored: nil)
|
|
102
|
+
@packet = packet
|
|
103
|
+
old_params = {}
|
|
104
|
+
old_params = get_params(show_ignored) if !show_ignored.nil?
|
|
105
|
+
old_params = set_existing(packet, existing) if existing
|
|
106
|
+
|
|
107
|
+
# Determine which items to display
|
|
108
|
+
target = System.targets[packet.target_name]
|
|
109
|
+
packet_items = packet.sorted_items
|
|
110
|
+
shown_packet_items = []
|
|
111
|
+
packet_items.each do |packet_item|
|
|
112
|
+
next if target && target.ignored_parameters.include?(packet_item.name) && !CmdParams.show_ignored
|
|
113
|
+
shown_packet_items << packet_item
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Destroy the old table widget and parameters
|
|
117
|
+
@table.dispose if @table
|
|
118
|
+
@table = nil
|
|
119
|
+
@param_widgets = []
|
|
120
|
+
row = 0
|
|
121
|
+
shown_packet_items.each do |packet_item|
|
|
122
|
+
value_item = nil
|
|
123
|
+
state_value_item = nil
|
|
124
|
+
@table = create_table(shown_packet_items.length) unless @table
|
|
125
|
+
|
|
126
|
+
# Parameter Name
|
|
127
|
+
item = Qt::TableWidgetItem.new("#{packet_item.name}:")
|
|
128
|
+
item.setTextAlignment(Qt::AlignRight | Qt::AlignVCenter)
|
|
129
|
+
item.setFlags(Qt::NoItemFlags | Qt::ItemIsSelectable | Qt::ItemIsEnabled)
|
|
130
|
+
@table.setItem(row, 0, item)
|
|
131
|
+
|
|
132
|
+
# Parameter Value
|
|
133
|
+
if packet_item.states
|
|
134
|
+
value_item, state_value_item = create_state_item(packet_item, old_params, row)
|
|
135
|
+
else
|
|
136
|
+
value_item = create_item(packet_item, old_params, row)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Units
|
|
140
|
+
item = Qt::TableWidgetItem.new(packet_item.units.to_s)
|
|
141
|
+
item.setTextAlignment(Qt::AlignRight | Qt::AlignVCenter)
|
|
142
|
+
item.setFlags(Qt::NoItemFlags | Qt::ItemIsSelectable | Qt::ItemIsEnabled)
|
|
143
|
+
@table.setItem(row, 3, item)
|
|
144
|
+
|
|
145
|
+
# Description
|
|
146
|
+
item = Qt::TableWidgetItem.new(packet_item.description.to_s)
|
|
147
|
+
item.setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter)
|
|
148
|
+
item.setFlags(Qt::NoItemFlags | Qt::ItemIsSelectable | Qt::ItemIsEnabled)
|
|
149
|
+
@table.setItem(row, 4, item)
|
|
150
|
+
|
|
151
|
+
@param_widgets << [packet_item, value_item, state_value_item]
|
|
152
|
+
row += 1
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
connect_table_item_changed() if @table
|
|
156
|
+
@table
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# If the user right clicks over a table item, this method displays a context
|
|
160
|
+
# menu with various options.
|
|
161
|
+
# @param point [Qt::Point] Point to display the context menu
|
|
162
|
+
def context_menu(point)
|
|
163
|
+
item = @table.itemAt(point)
|
|
164
|
+
if item
|
|
165
|
+
target_name = @packet.target_name
|
|
166
|
+
packet_name = @packet.packet_name
|
|
167
|
+
item_name = @table.item(item.row, 0).text[0..-2] # Remove :
|
|
168
|
+
if target_name.length > 0 && packet_name.length > 0 && item_name.length > 0
|
|
169
|
+
menu = Qt::Menu.new()
|
|
170
|
+
|
|
171
|
+
details_action = Qt::Action.new("Details #{target_name} #{packet_name} #{item_name}", self)
|
|
172
|
+
details_action.statusTip = "Popup details about #{target_name} #{packet_name} #{item_name}"
|
|
173
|
+
details_action.connect(SIGNAL('triggered()')) do
|
|
174
|
+
CmdDetailsDialog.new(nil, target_name, packet_name, item_name)
|
|
175
|
+
end
|
|
176
|
+
menu.addAction(details_action)
|
|
177
|
+
|
|
178
|
+
file_chooser_action = Qt::Action.new("Insert Filename", self)
|
|
179
|
+
file_chooser_action.statusTip = "Select a file and place its name into this parameter"
|
|
180
|
+
file_chooser_action.connect(SIGNAL('triggered()')) do
|
|
181
|
+
filename = Qt::FileDialog::getOpenFileName(self, "Insert Filename:", @file_dir, "All Files (*)")
|
|
182
|
+
if filename && !filename.empty?
|
|
183
|
+
@file_dir = File.dirname(filename)
|
|
184
|
+
_, value_item, state_value_item = @param_widgets[item.row]
|
|
185
|
+
if state_value_item
|
|
186
|
+
state_value_item.setText(filename)
|
|
187
|
+
elsif value_item
|
|
188
|
+
value_item.setText(filename)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
menu.addAction(file_chooser_action)
|
|
193
|
+
|
|
194
|
+
menu.exec(@table.mapToGlobal(point))
|
|
195
|
+
menu.dispose
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
private
|
|
201
|
+
|
|
202
|
+
def get_params(show_ignored)
|
|
203
|
+
params = {}
|
|
204
|
+
CmdParams.show_ignored = show_ignored
|
|
205
|
+
# Save parameter values
|
|
206
|
+
@param_widgets.each do |packet_item, value_item, state_value_item|
|
|
207
|
+
text = value_item.text
|
|
208
|
+
if state_value_item
|
|
209
|
+
params[packet_item.name] = [text, state_value_item.text]
|
|
210
|
+
else
|
|
211
|
+
params[packet_item.name] = text
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
params
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def set_existing(packet, existing)
|
|
218
|
+
params = {}
|
|
219
|
+
existing.each do |param_name, param_value|
|
|
220
|
+
packet_item = packet.items[param_name]
|
|
221
|
+
if packet_item.states
|
|
222
|
+
state_value = packet_item.states[param_value]
|
|
223
|
+
unless state_value # If we couldn't lookup the value by the name it's manual
|
|
224
|
+
state_value = param_value
|
|
225
|
+
param_value = MANUALLY
|
|
226
|
+
end
|
|
227
|
+
params[param_name] = [param_value.to_s, state_value.to_s]
|
|
228
|
+
else
|
|
229
|
+
params[param_name] = param_value.to_s
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
params
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def create_table(length)
|
|
236
|
+
table = Qt::TableWidget.new()
|
|
237
|
+
table.setSizePolicy(Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding)
|
|
238
|
+
table.setWordWrap(true)
|
|
239
|
+
table.setRowCount(length)
|
|
240
|
+
table.setColumnCount(5)
|
|
241
|
+
table.setHorizontalHeaderLabels(['Name', ' Value or State ', ' ', 'Units', 'Description'])
|
|
242
|
+
table.horizontalHeader.setStretchLastSection(true)
|
|
243
|
+
table.verticalHeader.setVisible(false)
|
|
244
|
+
table.setItemDelegate(CmdParamTableItemDelegate.new(table, @param_widgets, @production))
|
|
245
|
+
table.setContextMenuPolicy(Qt::CustomContextMenu)
|
|
246
|
+
table.verticalHeader.setResizeMode(Qt::HeaderView::ResizeToContents)
|
|
247
|
+
table.setEditTriggers(Qt::AbstractItemView::DoubleClicked | Qt::AbstractItemView::SelectedClicked | Qt::AbstractItemView::AnyKeyPressed)
|
|
248
|
+
table.setSelectionMode(Qt::AbstractItemView::NoSelection)
|
|
249
|
+
table.connect(SIGNAL('customContextMenuRequested(const QPoint&)')) {|point| context_menu(point) }
|
|
250
|
+
table.connect(SIGNAL('itemClicked(QTableWidgetItem*)')) do |item|
|
|
251
|
+
table.editItem(item) if (item.flags & Qt::ItemIsEditable) != 0
|
|
252
|
+
end
|
|
253
|
+
return table
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def create_state_item(packet_item, old_params, row)
|
|
257
|
+
default_state = packet_item.states.key(packet_item.default)
|
|
258
|
+
if old_params[packet_item.name]
|
|
259
|
+
value_item = Qt::TableWidgetItem.new(old_params[packet_item.name][0])
|
|
260
|
+
else
|
|
261
|
+
if default_state
|
|
262
|
+
value_item = Qt::TableWidgetItem.new(default_state.to_s)
|
|
263
|
+
elsif @production
|
|
264
|
+
value_item = Qt::TableWidgetItem.new(packet_item.states.keys[0])
|
|
265
|
+
else
|
|
266
|
+
value_item = Qt::TableWidgetItem.new(MANUALLY)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
value_item.setTextAlignment(Qt::AlignRight | Qt::AlignVCenter)
|
|
270
|
+
value_item.setFlags(Qt::NoItemFlags | Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable)
|
|
271
|
+
@table.setItem(row, 1, value_item)
|
|
272
|
+
|
|
273
|
+
state_value = packet_item.default.to_s
|
|
274
|
+
if old_params[packet_item.name]
|
|
275
|
+
state_value = old_params[packet_item.name][1]
|
|
276
|
+
end
|
|
277
|
+
is_integer = Integer(state_value) rescue false
|
|
278
|
+
if CmdParams.states_in_hex && is_integer
|
|
279
|
+
state_value_item = Qt::TableWidgetItem.new(sprintf("0x%X", state_value))
|
|
280
|
+
else
|
|
281
|
+
if state_value.is_printable?
|
|
282
|
+
state_value_item = Qt::TableWidgetItem.new(state_value)
|
|
283
|
+
else
|
|
284
|
+
state_value_item = Qt::TableWidgetItem.new("0x" + state_value.simple_formatted)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
state_value_item.setTextAlignment(Qt::AlignRight | Qt::AlignVCenter)
|
|
288
|
+
if @production
|
|
289
|
+
state_value_item.setFlags(Qt::NoItemFlags)
|
|
290
|
+
else
|
|
291
|
+
state_value_item.setFlags(Qt::NoItemFlags | Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable)
|
|
292
|
+
end
|
|
293
|
+
@table.setItem(row, 2, state_value_item)
|
|
294
|
+
|
|
295
|
+
# If the parameter is required clear the combobox and
|
|
296
|
+
# clear the value field so they have to choose something
|
|
297
|
+
if packet_item.required && !old_params[packet_item.name]
|
|
298
|
+
value_item.setText('')
|
|
299
|
+
state_value_item.setText('')
|
|
300
|
+
end
|
|
301
|
+
return [value_item, state_value_item]
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def create_item(packet_item, old_params, row)
|
|
305
|
+
if old_params[packet_item.name]
|
|
306
|
+
value_text = old_params[packet_item.name]
|
|
307
|
+
elsif packet_item.required
|
|
308
|
+
value_text = ''
|
|
309
|
+
else
|
|
310
|
+
if packet_item.format_string
|
|
311
|
+
begin
|
|
312
|
+
value_text = sprintf(packet_item.format_string, packet_item.default)
|
|
313
|
+
rescue
|
|
314
|
+
# Oh well - Don't use the format string
|
|
315
|
+
value_text = packet_item.default.to_s
|
|
316
|
+
end
|
|
317
|
+
else
|
|
318
|
+
value_text = packet_item.default.to_s
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
if !value_text.is_printable?
|
|
322
|
+
value_text = "0x" + value_text.simple_formatted
|
|
323
|
+
# Add quotes around STRING or BLOCK defaults so they are interpreted correctly
|
|
324
|
+
elsif (packet_item.data_type == :STRING or packet_item.data_type == :BLOCK)
|
|
325
|
+
value_text = "'#{packet_item.default}'"
|
|
326
|
+
end
|
|
327
|
+
value_item = Qt::TableWidgetItem.new(value_text)
|
|
328
|
+
value_item.setTextAlignment(Qt::AlignRight | Qt::AlignVCenter)
|
|
329
|
+
value_item.setFlags(Qt::NoItemFlags | Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable)
|
|
330
|
+
@table.setItem(row, 1, value_item)
|
|
331
|
+
@table.setSpan(row, 1, 1, 2)
|
|
332
|
+
return value_item
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def connect_table_item_changed
|
|
336
|
+
@table.connect(SIGNAL('itemChanged(QTableWidgetItem*)')) do |item|
|
|
337
|
+
packet_item, value_item, state_value_item = @param_widgets[item.row]
|
|
338
|
+
if item.column == 1
|
|
339
|
+
if packet_item.states
|
|
340
|
+
value = packet_item.states[value_item.text]
|
|
341
|
+
@table.blockSignals(true)
|
|
342
|
+
if CmdParams.states_in_hex && value.kind_of?(Integer)
|
|
343
|
+
state_value_item.setText(sprintf("0x%X", value))
|
|
344
|
+
else
|
|
345
|
+
state_value_item.setText(value.to_s)
|
|
346
|
+
end
|
|
347
|
+
@table.blockSignals(false)
|
|
348
|
+
end
|
|
349
|
+
elsif item.column == 2
|
|
350
|
+
@table.blockSignals(true)
|
|
351
|
+
@table.item(item.row, 1).setText(MANUALLY)
|
|
352
|
+
@table.blockSignals(false)
|
|
353
|
+
end
|
|
354
|
+
emit modified()
|
|
355
|
+
end
|
|
356
|
+
@table.resizeColumnsToContents()
|
|
357
|
+
@table.resizeRowsToContents()
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|