cosmos 4.0.3-java → 4.1.0-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/.travis.yml +5 -5
- data/Manifest.txt +11 -1
- data/README.md +3 -2
- data/Rakefile +18 -4
- data/appveyor.yml +19 -0
- data/cosmos.gemspec +12 -3
- data/data/config/cmd_tlm_server.yaml +3 -0
- data/data/crc.txt +63 -60
- data/demo/config/targets/INST/cmd_tlm_server.txt +1 -0
- data/demo/config/targets/INST/cmd_tlm_server2.txt +7 -0
- data/demo/config/tools/cmd_sequence/cmd_sequence.txt +2 -0
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +8 -12
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +7 -9
- data/demo/lib/cmd_sequence_exporter.rb +52 -0
- data/demo/lib/example_background_task.rb +1 -0
- data/demo/procedures/replay_test.rb +32 -0
- data/ext/cosmos/ext/structure/structure.c +39 -3
- data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +1 -0
- data/install/config/tools/launcher/launcher.txt +2 -0
- data/lib/cosmos/config/config_parser.rb +2 -0
- data/lib/cosmos/core_ext/io.rb +89 -60
- data/lib/cosmos/gui/qt.rb +5 -8
- data/lib/cosmos/gui/qt_tool.rb +8 -8
- data/lib/cosmos/gui/text/ruby_editor.rb +12 -12
- data/lib/cosmos/gui/utilities/script_module_gui.rb +9 -9
- data/lib/cosmos/gui/widgets/realtime_button_bar.rb +18 -17
- data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +2 -2
- data/lib/cosmos/interfaces/protocols/template_protocol.rb +3 -0
- data/lib/cosmos/interfaces/udp_interface.rb +27 -14
- data/lib/cosmos/io/buffered_file.rb +0 -1
- data/lib/cosmos/io/json_drb.rb +134 -214
- data/lib/cosmos/io/json_drb_object.rb +22 -61
- data/lib/cosmos/io/json_drb_rack.rb +79 -0
- data/lib/cosmos/io/json_rpc.rb +27 -0
- data/lib/cosmos/io/udp_sockets.rb +102 -58
- data/lib/cosmos/packets/commands.rb +1 -1
- data/lib/cosmos/packets/structure.rb +1 -1
- data/lib/cosmos/packets/structure_item.rb +37 -5
- data/lib/cosmos/script/cmd_tlm_server.rb +76 -2
- data/lib/cosmos/script/replay.rb +60 -0
- data/lib/cosmos/script/script.rb +20 -2
- data/lib/cosmos/script/scripting.rb +9 -9
- data/lib/cosmos/script/tools.rb +14 -0
- data/lib/cosmos/system/system.rb +185 -92
- data/lib/cosmos/system/target.rb +1 -1
- data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +44 -4
- data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +4 -0
- data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +7 -0
- data/lib/cosmos/tools/cmd_tlm_server/api.rb +347 -20
- data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +3 -0
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +329 -111
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +13 -0
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +261 -95
- data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +46 -35
- data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +18 -8
- data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +39 -28
- data/lib/cosmos/tools/cmd_tlm_server/gui/replay_tab.rb +242 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +24 -8
- data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +18 -6
- data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +5 -4
- data/lib/cosmos/tools/cmd_tlm_server/replay_backend.rb +375 -0
- data/lib/cosmos/tools/cmd_tlm_server/routers.rb +10 -2
- data/lib/cosmos/tools/data_viewer/data_viewer.rb +40 -5
- data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +18 -20
- data/lib/cosmos/tools/launcher/launcher_config.rb +5 -16
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +65 -39
- data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +19 -0
- data/lib/cosmos/tools/replay/replay.rb +5 -505
- data/lib/cosmos/tools/script_runner/script_audit.rb +1 -0
- data/lib/cosmos/tools/script_runner/script_runner.rb +3 -4
- data/lib/cosmos/tools/script_runner/script_runner_config.rb +3 -4
- data/lib/cosmos/tools/script_runner/script_runner_frame.rb +44 -23
- data/lib/cosmos/tools/test_runner/results_writer.rb +4 -0
- data/lib/cosmos/tools/test_runner/test_runner.rb +0 -3
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +6 -2
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +26 -1
- data/lib/cosmos/tools/tlm_viewer/screen.rb +24 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +25 -0
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +24 -14
- data/lib/cosmos/top_level.rb +34 -24
- data/lib/cosmos/utilities/csv.rb +60 -8
- data/lib/cosmos/version.rb +5 -5
- data/spec/config/config_parser_spec.rb +10 -1
- data/spec/core_ext/socket_spec.rb +4 -2
- data/spec/gui/utilities/script_module_gui_spec.rb +102 -0
- data/spec/install/config/data/data.txt +1 -0
- data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +2 -0
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +1 -2
- data/spec/interfaces/protocols/template_protocol_spec.rb +72 -2
- data/spec/interfaces/serial_interface_spec.rb +1 -1
- data/spec/interfaces/udp_interface_spec.rb +14 -0
- data/spec/io/buffered_file_spec.rb +37 -0
- data/spec/io/json_drb_object_spec.rb +2 -15
- data/spec/io/json_drb_spec.rb +61 -121
- data/spec/io/udp_sockets_spec.rb +42 -2
- data/spec/packet_logs/packet_log_reader_spec.rb +5 -2
- data/spec/packets/binary_accessor_spec.rb +1 -1
- data/spec/packets/packet_item_spec.rb +1 -1
- data/spec/packets/structure_item_spec.rb +5 -6
- data/spec/script/cmd_tlm_server_spec.rb +39 -4
- data/spec/script/commands_disconnect_spec.rb +1 -1
- data/spec/script/commands_spec.rb +2 -1
- data/spec/script/scripting_spec.rb +18 -3
- data/spec/script/telemetry_spec.rb +5 -0
- data/spec/spec_helper.rb +43 -26
- data/spec/streams/tcpip_socket_stream_spec.rb +2 -2
- data/spec/system/system_spec.rb +11 -9
- data/spec/system/target_spec.rb +3 -0
- data/spec/tools/cmd_tlm_server/api_spec.rb +543 -29
- data/spec/tools/cmd_tlm_server/background_task_spec.rb +2 -2
- data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +31 -75
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +199 -66
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +85 -9
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +29 -127
- data/spec/tools/cmd_tlm_server/router_thread_spec.rb +10 -50
- data/spec/tools/launcher/launcher_config_spec.rb +1 -1
- data/spec/tools/table_manager/table_item_spec.rb +1 -1
- data/spec/tools/table_manager/tablemanager_core_spec.rb +4 -4
- data/spec/top_level/top_level_spec.rb +151 -3
- data/spec/utilities/csv_spec.rb +24 -5
- metadata +61 -9
- data/lib/cosmos/tools/replay/replay_server.rb +0 -91
data/lib/cosmos/top_level.rb
CHANGED
|
@@ -169,9 +169,8 @@ module Cosmos
|
|
|
169
169
|
return filename if File.exist? filename
|
|
170
170
|
|
|
171
171
|
# Check relative to executing file
|
|
172
|
-
filename = Cosmos.path($0, 'config
|
|
172
|
+
filename = Cosmos.path($0, ['config', 'data', name])
|
|
173
173
|
return filename if File.exist? filename
|
|
174
|
-
|
|
175
174
|
nil
|
|
176
175
|
end
|
|
177
176
|
|
|
@@ -192,7 +191,7 @@ module Cosmos
|
|
|
192
191
|
else
|
|
193
192
|
current_dir = File.join(BASE_PWD, calling_file)
|
|
194
193
|
end
|
|
195
|
-
|
|
194
|
+
loop do
|
|
196
195
|
test_path = File.join(current_dir, partial_path)
|
|
197
196
|
if File.exist?(test_path)
|
|
198
197
|
return test_path
|
|
@@ -298,13 +297,14 @@ module Cosmos
|
|
|
298
297
|
thread = Thread.new do
|
|
299
298
|
output, _ = Open3.capture2e(command)
|
|
300
299
|
if !output.empty?
|
|
301
|
-
#
|
|
302
|
-
|
|
300
|
+
# Ignore modalSession messages on Mac Mavericks and Qt Untested Windows 10
|
|
301
|
+
new_output = ''
|
|
303
302
|
output.each_line do |line|
|
|
304
|
-
|
|
303
|
+
new_output << line if line !~ /modalSession/ && line !~ /Untested Windows version 10.0/
|
|
305
304
|
end
|
|
305
|
+
output = new_output
|
|
306
306
|
|
|
307
|
-
if
|
|
307
|
+
if !output.empty?
|
|
308
308
|
Logger.error output
|
|
309
309
|
self.write_unexpected_file(output)
|
|
310
310
|
if defined? ::Qt and $qApp
|
|
@@ -395,7 +395,7 @@ module Cosmos
|
|
|
395
395
|
# @yieldparam file [File] The log file
|
|
396
396
|
# @return [String|nil] The fully pathed log file name or nil if there was
|
|
397
397
|
# an error creating the log file.
|
|
398
|
-
def self.create_log_file(filename, log_dir)
|
|
398
|
+
def self.create_log_file(filename, log_dir = nil)
|
|
399
399
|
log_file = nil
|
|
400
400
|
Cosmos.set_working_dir do
|
|
401
401
|
begin
|
|
@@ -403,31 +403,34 @@ module Cosmos
|
|
|
403
403
|
# system.txt configuration file. If this has an error we won't be able
|
|
404
404
|
# to determine the log path but we still want to write the log.
|
|
405
405
|
log_dir = System.instance.paths['LOGS'] unless log_dir
|
|
406
|
-
log_file = File.join(log_dir,
|
|
407
|
-
File.build_timestamped_filename([filename]))
|
|
408
406
|
# Make sure the log directory exists
|
|
409
407
|
raise unless File.exist?(log_dir)
|
|
410
|
-
log_file
|
|
411
408
|
rescue Exception
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
else
|
|
418
|
-
|
|
419
|
-
|
|
409
|
+
log_dir = nil # Reset log dir since it failed above
|
|
410
|
+
# First check for ./logs
|
|
411
|
+
log_dir = './logs' if File.exist?('./logs')
|
|
412
|
+
# Prefer ./outputs/logs if it exists
|
|
413
|
+
log_dir = './outputs/logs' if File.exist?('./outputs/logs')
|
|
414
|
+
# If all else fails just use the local directory
|
|
415
|
+
log_dir = '.' unless log_dir
|
|
416
|
+
end
|
|
417
|
+
log_file = File.join(log_dir,
|
|
418
|
+
File.build_timestamped_filename([filename]))
|
|
419
|
+
# Check for the log file existing. This could happen if this method gets
|
|
420
|
+
# called more than once in the same second.
|
|
421
|
+
if File.exist?(log_file)
|
|
422
|
+
sleep 1.01 # Sleep before rebuilding the timestamp to get something unique
|
|
423
|
+
log_file = File.join(log_dir,
|
|
424
|
+
File.build_timestamped_filename([filename]))
|
|
420
425
|
end
|
|
421
426
|
begin
|
|
422
|
-
# Log exception to file, open the file in append mode in case we get
|
|
423
|
-
# multiple exceptions in the same second. That way we don't lose
|
|
424
|
-
# exceptions by overwritting the last exception file.
|
|
425
427
|
COSMOS_MUTEX.synchronize do
|
|
426
428
|
begin
|
|
427
|
-
file = File.open(log_file, '
|
|
429
|
+
file = File.open(log_file, 'w')
|
|
428
430
|
yield file
|
|
429
431
|
ensure
|
|
430
432
|
file.close unless file.closed?
|
|
433
|
+
File.chmod(0444, log_file) # Make file read only
|
|
431
434
|
end
|
|
432
435
|
end
|
|
433
436
|
rescue Exception
|
|
@@ -738,8 +741,15 @@ module Cosmos
|
|
|
738
741
|
Logger.info "Thread owner #{owner.class} does not support graceful_kill"
|
|
739
742
|
end
|
|
740
743
|
if thread.alive?
|
|
744
|
+
# If the thread dies after alive? but before backtrace, bt will be nil.
|
|
745
|
+
bt = thread.backtrace
|
|
746
|
+
|
|
741
747
|
# Graceful failed
|
|
742
|
-
|
|
748
|
+
msg = "Failed to gracefully kill thread:\n"
|
|
749
|
+
msg << " Caller Backtrace:\n #{caller().join("\n ")}\n"
|
|
750
|
+
msg << " \n Thread Backtrace:\n #{bt.join("\n ")}\n" if bt
|
|
751
|
+
msg << "\n"
|
|
752
|
+
Logger.warn msg
|
|
743
753
|
thread.kill
|
|
744
754
|
end_time = Time.now.sys + hard_timeout
|
|
745
755
|
while thread.alive? && ((end_time - Time.now.sys) > 0)
|
data/lib/cosmos/utilities/csv.rb
CHANGED
|
@@ -51,13 +51,26 @@ module Cosmos
|
|
|
51
51
|
# @return [Boolean] Single value converted to a boolean (true or false)
|
|
52
52
|
def bool(item, index = 0)
|
|
53
53
|
raise "#{item} not found" unless keys.include?(item)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
if Range === index
|
|
55
|
+
@hash[item][index].map do |x|
|
|
56
|
+
case x.upcase
|
|
57
|
+
when 'TRUE'
|
|
58
|
+
true
|
|
59
|
+
when 'FALSE'
|
|
60
|
+
false
|
|
61
|
+
else
|
|
62
|
+
raise "#{item} value of #{x} not boolean. Must be 'TRUE' 'or 'FALSE'."
|
|
63
|
+
end
|
|
64
|
+
end
|
|
59
65
|
else
|
|
60
|
-
|
|
66
|
+
case @hash[item][index].upcase
|
|
67
|
+
when 'TRUE'
|
|
68
|
+
true
|
|
69
|
+
when 'FALSE'
|
|
70
|
+
false
|
|
71
|
+
else
|
|
72
|
+
raise "#{item} value of #{@hash[item][index]} not boolean. Must be 'TRUE' 'or 'FALSE'."
|
|
73
|
+
end
|
|
61
74
|
end
|
|
62
75
|
end
|
|
63
76
|
alias boolean bool
|
|
@@ -69,7 +82,11 @@ module Cosmos
|
|
|
69
82
|
# @return [Integer] Single value converted to an integer
|
|
70
83
|
def int(item, index = 0)
|
|
71
84
|
raise "#{item} not found" unless keys.include?(item)
|
|
72
|
-
|
|
85
|
+
if Range === index
|
|
86
|
+
@hash[item][index].map {|x| x.to_i }
|
|
87
|
+
else
|
|
88
|
+
@hash[item][index].to_i
|
|
89
|
+
end
|
|
73
90
|
end
|
|
74
91
|
alias integer int
|
|
75
92
|
|
|
@@ -80,8 +97,42 @@ module Cosmos
|
|
|
80
97
|
# @return [Float] Single value converted to a float
|
|
81
98
|
def float(item, index = 0)
|
|
82
99
|
raise "#{item} not found" unless keys.include?(item)
|
|
83
|
-
|
|
100
|
+
if Range === index
|
|
101
|
+
@hash[item][index].map {|x| x.to_f }
|
|
102
|
+
else
|
|
103
|
+
@hash[item][index].to_f
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Convenience method to access a value by key and convert it to a string
|
|
108
|
+
#
|
|
109
|
+
# @param item [String] Key to access the value
|
|
110
|
+
# @param index [Integer] Which value to return
|
|
111
|
+
# @return [String] Single value converted to a string
|
|
112
|
+
def string(item, index = 0)
|
|
113
|
+
raise "#{item} not found" unless keys.include?(item)
|
|
114
|
+
if Range === index
|
|
115
|
+
@hash[item][index].map {|x| x.to_s }
|
|
116
|
+
else
|
|
117
|
+
@hash[item][index].to_s
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
alias str string
|
|
121
|
+
|
|
122
|
+
# Convenience method to access a value by key and convert it to a symbol
|
|
123
|
+
#
|
|
124
|
+
# @param item [String] Key to access the value
|
|
125
|
+
# @param index [Integer] Which value to return
|
|
126
|
+
# @return [Symbol] Single value converted to a symbol
|
|
127
|
+
def symbol(item, index = 0)
|
|
128
|
+
raise "#{item} not found" unless keys.include?(item)
|
|
129
|
+
if Range === index
|
|
130
|
+
@hash[item][index].map {|x| x.intern }
|
|
131
|
+
else
|
|
132
|
+
@hash[item][index].intern
|
|
133
|
+
end
|
|
84
134
|
end
|
|
135
|
+
alias sym symbol
|
|
85
136
|
|
|
86
137
|
# Creates a copy of the CSV file passed into the constructor. The file will
|
|
87
138
|
# be prefixed by the current date and time to create a unique filename.
|
|
@@ -131,6 +182,7 @@ module Cosmos
|
|
|
131
182
|
# Closes the archive file created by #{CSV#create_archive}.
|
|
132
183
|
def close_archive
|
|
133
184
|
@archive.close
|
|
185
|
+
File.chmod(0444, @archive_file)
|
|
134
186
|
@archive = nil
|
|
135
187
|
end
|
|
136
188
|
end
|
data/lib/cosmos/version.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
2
|
|
|
3
|
-
COSMOS_VERSION = '4.0
|
|
3
|
+
COSMOS_VERSION = '4.1.0'
|
|
4
4
|
module Cosmos
|
|
5
5
|
module Version
|
|
6
6
|
MAJOR = '4'
|
|
7
|
-
MINOR = '
|
|
8
|
-
PATCH = '
|
|
9
|
-
BUILD = '
|
|
7
|
+
MINOR = '1'
|
|
8
|
+
PATCH = '0'
|
|
9
|
+
BUILD = '9731591f6e6dd90749a966e06a95d923b7f112ae'
|
|
10
10
|
end
|
|
11
|
-
VERSION = '4.0
|
|
11
|
+
VERSION = '4.1.0'
|
|
12
12
|
end
|
|
@@ -67,8 +67,17 @@ module Cosmos
|
|
|
67
67
|
tf.unlink
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
it "requires ERB partials begin with an underscore" do
|
|
71
|
+
tf = Tempfile.new('unittest')
|
|
72
|
+
tf.puts "<%= render 'partial.txt' %>"
|
|
73
|
+
tf.close
|
|
74
|
+
|
|
75
|
+
expect { @cp.parse_file(tf.path) }.to raise_error(ConfigParser::Error, /must begin with an underscore/)
|
|
76
|
+
tf.unlink
|
|
77
|
+
end
|
|
78
|
+
|
|
70
79
|
it "supports ERB partials via render" do
|
|
71
|
-
tf2 = Tempfile.new('
|
|
80
|
+
tf2 = Tempfile.new('_partial.txt')
|
|
72
81
|
tf2.puts '<% if output %>'
|
|
73
82
|
tf2.puts 'KEYWORD <%= id %> <%= desc %>'
|
|
74
83
|
tf2.puts '<% end %>'
|
|
@@ -25,8 +25,10 @@ describe Socket do
|
|
|
25
25
|
|
|
26
26
|
describe "lookup_hostname_from_ip" do
|
|
27
27
|
it "returns the hostname for the ip address" do
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
if !ENV['APPVEYOR']
|
|
29
|
+
ipaddr = Resolv.getaddress "localhost"
|
|
30
|
+
expect(Socket.lookup_hostname_from_ip(ipaddr)).to match "localhost"
|
|
31
|
+
end
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
if RUBY_ENGINE == 'ruby'
|
|
12
|
+
require 'spec_helper'
|
|
13
|
+
require 'cosmos/gui/qt'
|
|
14
|
+
require 'cosmos/script'
|
|
15
|
+
require 'cosmos/gui/utilities/script_module_gui'
|
|
16
|
+
|
|
17
|
+
module Cosmos
|
|
18
|
+
describe Script do
|
|
19
|
+
after(:all) do
|
|
20
|
+
# Load the original scripting file over the script_module_gui
|
|
21
|
+
load 'cosmos/script/scripting.rb'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def stub_null_object(constant)
|
|
25
|
+
class_double(constant).tap do |double|
|
|
26
|
+
stub_const(constant, double)
|
|
27
|
+
allow(double).to receive(:new).and_return(double(constant).as_null_object)
|
|
28
|
+
yield double if block_given?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
let!(:qt_module) do
|
|
33
|
+
class_double('Qt').as_stubbed_const(:transfer_nested_constants => true).tap do |double|
|
|
34
|
+
stub_const('Qt', double)
|
|
35
|
+
stub_const('Qt::WindowTitleHint', double)
|
|
36
|
+
stub_const('Qt::WindowSystemMenuHint', double)
|
|
37
|
+
allow(double).to receive(:execute_in_main_thread).and_yield
|
|
38
|
+
allow(double).to receive(:debug_level)
|
|
39
|
+
end
|
|
40
|
+
stub_null_object('Qt::Widget')
|
|
41
|
+
stub_null_object('Qt::Dialog') do |double|
|
|
42
|
+
instance = double("Qt::Dialog").as_null_object
|
|
43
|
+
allow(instance).to receive(:exec).and_return 1 # break the loop by returning 1
|
|
44
|
+
allow(double).to receive(:new).and_return(instance)
|
|
45
|
+
end
|
|
46
|
+
# Stub Accepted to be 1 to match the instance exec returning 1
|
|
47
|
+
stub_const('Qt::Dialog::Accepted', 1)
|
|
48
|
+
stub_null_object('Qt::VBoxLayout')
|
|
49
|
+
stub_null_object('Qt::HBoxLayout')
|
|
50
|
+
stub_null_object('Qt::Label')
|
|
51
|
+
stub_null_object('Qt::PushButton')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "combo_box" do
|
|
55
|
+
it "should not modify the inputs" do
|
|
56
|
+
class_double('Cosmos::ComboboxChooser').as_stubbed_const.tap do |double|
|
|
57
|
+
chooser = double("ComboboxChooser").as_null_object
|
|
58
|
+
allow(chooser).to receive(:sel_command_callback=) do |args|
|
|
59
|
+
# Simulate the user clicking the TEST option in the combobox
|
|
60
|
+
args.call("TEST")
|
|
61
|
+
end
|
|
62
|
+
allow(double).to receive(:new).and_return(chooser)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
buttons = %w(THIS IS A TEST)
|
|
66
|
+
answer = combo_box("HI", *buttons)
|
|
67
|
+
expect(buttons).to eq %w(THIS IS A TEST)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "message_box" do
|
|
72
|
+
it "should not modify the inputs" do
|
|
73
|
+
class_double('Qt::MessageBox').as_stubbed_const.tap do |double|
|
|
74
|
+
msg_box = double("MessageBox").as_null_object
|
|
75
|
+
allow(msg_box).to receive_message_chain(:clickedButton, :text).and_return("TEST")
|
|
76
|
+
allow(double).to receive(:new).and_return(msg_box)
|
|
77
|
+
stub_const('Qt::MessageBox::AcceptRole', 1)
|
|
78
|
+
stub_const('Qt::MessageBox::RejectRole', 0)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
buttons = %w(THIS IS A TEST)
|
|
82
|
+
answer = message_box("HI", *buttons)
|
|
83
|
+
expect(buttons).to eq %w(THIS IS A TEST)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe "vertical_message_box" do
|
|
88
|
+
it "should not modify the inputs" do
|
|
89
|
+
stub_null_object('Qt::PushButton') do |double|
|
|
90
|
+
instance = double("Qt::PushButton").as_null_object
|
|
91
|
+
allow(instance).to receive(:connect).and_yield
|
|
92
|
+
allow(double).to receive(:new).and_return(instance)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
buttons = %w(THIS IS A TEST)
|
|
96
|
+
answer = vertical_message_box("HI", *buttons)
|
|
97
|
+
expect(buttons).to eq %w(THIS IS A TEST)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# This is data
|
|
@@ -89,6 +89,8 @@ COMMAND INST ARYCMD BIG_ENDIAN "Command with array parameter"
|
|
|
89
89
|
PARAMETER CCSDSLENGTH 32 16 UINT 0 65535 0 "CCSDS primary header packet length"
|
|
90
90
|
ID_PARAMETER PKTID 48 16 UINT 0 65535 6 "Packet id"
|
|
91
91
|
ARRAY_PARAMETER ARRAY 64 64 FLOAT 640 "Array parameter"
|
|
92
|
+
APPEND_ARRAY_PARAMETER ARRAY2 32 UINT 320 "Array parameter"
|
|
93
|
+
FORMAT_STRING "0x%0X"
|
|
92
94
|
|
|
93
95
|
COMMAND INST SLRPNLDEPLOY BIG_ENDIAN "Deploy solar array panels"
|
|
94
96
|
PARAMETER CCSDSVER 0 3 UINT 0 0 0 "CCSDS primary header version number"
|
|
@@ -32,8 +32,7 @@ module Cosmos
|
|
|
32
32
|
allow_any_instance_of(Interface).to receive(:connected?).and_return(true)
|
|
33
33
|
allow_any_instance_of(Interface).to receive(:disconnect)
|
|
34
34
|
@cts = CmdTlmServer.new
|
|
35
|
-
|
|
36
|
-
sleep 0.1
|
|
35
|
+
sleep 1
|
|
37
36
|
@ctsi = CmdTlmServerInterface.new
|
|
38
37
|
end
|
|
39
38
|
|
|
@@ -173,7 +173,7 @@ module Cosmos
|
|
|
173
173
|
@interface.write(packet)
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
-
it "processes responses" do
|
|
176
|
+
it "processes responses with no ID fields" do
|
|
177
177
|
rsp_pkt = Packet.new('TGT', 'READ_VOLTAGE')
|
|
178
178
|
rsp_pkt.append_item("VOLTAGE", 16, :UINT)
|
|
179
179
|
allow(System).to receive_message_chain(:telemetry, :packet).and_return(rsp_pkt)
|
|
@@ -199,7 +199,77 @@ module Cosmos
|
|
|
199
199
|
@interface.write(packet)
|
|
200
200
|
sleep 0.55
|
|
201
201
|
expect($write_buffer).to eql("SOUR:VOLT 11, (@1)\xAB\xCD")
|
|
202
|
-
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "sets the response ID to the defined ID value" do
|
|
205
|
+
rsp_pkt = Packet.new('TGT', 'READ_VOLTAGE')
|
|
206
|
+
rsp_pkt.append_item("PKT_ID", 16, :UINT, nil, :BIG_ENDIAN, :ERROR, nil, nil, nil, 1) # ID == 1
|
|
207
|
+
rsp_pkt.append_item("VOLTAGE", 16, :UINT)
|
|
208
|
+
allow(System).to receive_message_chain(:telemetry, :packet).and_return(rsp_pkt)
|
|
209
|
+
@interface.instance_variable_set(:@stream, TemplateStream.new)
|
|
210
|
+
@interface.add_protocol(TemplateProtocol, %w(0xABCD 0xABCD 0 nil 1 true 0 nil false nil nil), :READ_WRITE)
|
|
211
|
+
@interface.target_names = ['TGT']
|
|
212
|
+
packet = Packet.new('TGT', 'CMD')
|
|
213
|
+
packet.append_item("CMD_ID", 16, :UINT, nil, :BIG_ENDIAN, :ERROR, nil, nil, nil, 1) # ID == 1
|
|
214
|
+
packet.get_item("CMD_ID").default = 1
|
|
215
|
+
packet.append_item("VOLTAGE", 16, :UINT)
|
|
216
|
+
packet.get_item("VOLTAGE").default = 11
|
|
217
|
+
packet.append_item("CHANNEL", 16, :UINT)
|
|
218
|
+
packet.get_item("CHANNEL").default = 1
|
|
219
|
+
packet.append_item("CMD_TEMPLATE", 1024, :STRING)
|
|
220
|
+
packet.get_item("CMD_TEMPLATE").default = "SOUR:VOLT <VOLTAGE>, (@<CHANNEL>)"
|
|
221
|
+
packet.append_item("RSP_TEMPLATE", 1024, :STRING)
|
|
222
|
+
packet.get_item("RSP_TEMPLATE").default = "<VOLTAGE>"
|
|
223
|
+
packet.append_item("RSP_PACKET", 1024, :STRING)
|
|
224
|
+
packet.get_item("RSP_PACKET").default = "READ_VOLTAGE"
|
|
225
|
+
packet.restore_defaults
|
|
226
|
+
@interface.connect
|
|
227
|
+
read_result = nil
|
|
228
|
+
$read_buffer = "\x31\x30\xAB\xCD" # ASCII 31, 30 is '10'
|
|
229
|
+
Thread.new { sleep(0.5); read_result = @interface.read }
|
|
230
|
+
@interface.write(packet)
|
|
231
|
+
sleep 0.55
|
|
232
|
+
expect($write_buffer).to eql("SOUR:VOLT 11, (@1)\xAB\xCD")
|
|
233
|
+
expect(read_result.read("PKT_ID")).to eql(1) # Result ID set to the defined value
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it "handles multiple response IDs" do
|
|
237
|
+
rsp_pkt = Packet.new('TGT', 'READ_VOLTAGE')
|
|
238
|
+
rsp_pkt.append_item("APID", 16, :UINT, nil, :BIG_ENDIAN, :ERROR, nil, nil, nil, 10) # ID == 10
|
|
239
|
+
rsp_pkt.append_item("PKTID", 16, :UINT, nil, :BIG_ENDIAN, :ERROR, nil, nil, nil, 20) # ID == 20
|
|
240
|
+
rsp_pkt.append_item("VOLTAGE", 16, :UINT)
|
|
241
|
+
allow(System).to receive_message_chain(:telemetry, :packet).and_return(rsp_pkt)
|
|
242
|
+
@interface.instance_variable_set(:@stream, TemplateStream.new)
|
|
243
|
+
@interface.add_protocol(TemplateProtocol, %w(0xABCD 0xABCD 0 nil 1 true 0 nil false nil nil), :READ_WRITE)
|
|
244
|
+
@interface.target_names = ['TGT']
|
|
245
|
+
packet = Packet.new('TGT', 'CMD')
|
|
246
|
+
packet.append_item("APID", 16, :UINT, nil, :BIG_ENDIAN, :ERROR, nil, nil, nil, 1) # ID == 1
|
|
247
|
+
packet.get_item("APID").default = 1
|
|
248
|
+
packet.append_item("PKTID", 16, :UINT, nil, :BIG_ENDIAN, :ERROR, nil, nil, nil, 2) # ID == 2
|
|
249
|
+
packet.get_item("PKTID").default = 2
|
|
250
|
+
packet.append_item("VOLTAGE", 16, :UINT)
|
|
251
|
+
packet.get_item("VOLTAGE").default = 11
|
|
252
|
+
packet.append_item("CHANNEL", 16, :UINT)
|
|
253
|
+
packet.get_item("CHANNEL").default = 1
|
|
254
|
+
packet.append_item("CMD_TEMPLATE", 1024, :STRING)
|
|
255
|
+
packet.get_item("CMD_TEMPLATE").default = "SOUR:VOLT <VOLTAGE>, (@<CHANNEL>)"
|
|
256
|
+
packet.append_item("RSP_TEMPLATE", 1024, :STRING)
|
|
257
|
+
packet.get_item("RSP_TEMPLATE").default = "<VOLTAGE>"
|
|
258
|
+
packet.append_item("RSP_PACKET", 1024, :STRING)
|
|
259
|
+
packet.get_item("RSP_PACKET").default = "READ_VOLTAGE"
|
|
260
|
+
packet.restore_defaults
|
|
261
|
+
# Explicitly write in values to the ID items different than the defaults
|
|
262
|
+
packet.write("APID", 10)
|
|
263
|
+
packet.write("PKTID", 20)
|
|
264
|
+
@interface.connect
|
|
265
|
+
read_result = nil
|
|
266
|
+
$read_buffer = "\x31\x30\xAB\xCD" # ASCII 31, 30 is '10'
|
|
267
|
+
Thread.new { sleep(0.5); read_result = @interface.read }
|
|
268
|
+
@interface.write(packet)
|
|
269
|
+
sleep 0.55
|
|
270
|
+
expect($write_buffer).to eql("SOUR:VOLT 11, (@1)\xAB\xCD")
|
|
271
|
+
expect(read_result.read("APID")).to eql(10) # ID item set to the defined value
|
|
272
|
+
expect(read_result.read("PKTID")).to eql(20) # ID item set to the defined value
|
|
203
273
|
end
|
|
204
274
|
|
|
205
275
|
it "handles templates with more values than the response" do
|