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
|
@@ -34,6 +34,8 @@ module Cosmos
|
|
|
34
34
|
# calling the 'call' method once.
|
|
35
35
|
# @param index [Integer] Which background task to start
|
|
36
36
|
def start(index)
|
|
37
|
+
raise "No task at index #{index}. There are #{@config.background_tasks.length} total tasks." unless index < @config.background_tasks.length
|
|
38
|
+
return if @threads[index] # Don't re-create a running thread. They must call stop first.
|
|
37
39
|
@threads[index] = Thread.new do
|
|
38
40
|
@config.background_tasks[index].thread = Thread.current
|
|
39
41
|
begin
|
|
@@ -56,6 +58,7 @@ module Cosmos
|
|
|
56
58
|
# Ruby thread.
|
|
57
59
|
# @param index [Integer] Which background task to stop
|
|
58
60
|
def stop(index)
|
|
61
|
+
raise "No task at index #{index}. There are #{@config.background_tasks.length} total tasks." unless index < @config.background_tasks.length
|
|
59
62
|
begin
|
|
60
63
|
@config.background_tasks[index].stop
|
|
61
64
|
rescue
|
|
@@ -17,6 +17,7 @@ require 'cosmos/tools/cmd_tlm_server/commanding'
|
|
|
17
17
|
require 'cosmos/tools/cmd_tlm_server/interfaces'
|
|
18
18
|
require 'cosmos/tools/cmd_tlm_server/packet_logging'
|
|
19
19
|
require 'cosmos/tools/cmd_tlm_server/routers'
|
|
20
|
+
require 'cosmos/tools/cmd_tlm_server/replay_backend'
|
|
20
21
|
|
|
21
22
|
module Cosmos
|
|
22
23
|
|
|
@@ -39,6 +40,8 @@ module Cosmos
|
|
|
39
40
|
instance_attr_reader :packet_logging
|
|
40
41
|
# @return [Routers] Access to the routers
|
|
41
42
|
instance_attr_reader :routers
|
|
43
|
+
# @return [ReplayBackend] Access to replay logic
|
|
44
|
+
instance_attr_reader :replay_backend
|
|
42
45
|
# @return [MessageLog] Message log for the CmdTlmServer
|
|
43
46
|
instance_attr_reader :message_log
|
|
44
47
|
# @return [JsonDRb] Provides access to the server for all tools both
|
|
@@ -46,6 +49,8 @@ module Cosmos
|
|
|
46
49
|
instance_attr_accessor :json_drb
|
|
47
50
|
# @return [String] CmdTlmServer title as set in the config file
|
|
48
51
|
instance_attr_accessor :title
|
|
52
|
+
# @return [Symbol] mode :CMD_TLM_SERVER or :REPLAY
|
|
53
|
+
instance_attr_accessor :mode
|
|
49
54
|
|
|
50
55
|
# attr_reader attributes are only used by CmdTlmServer internally and are
|
|
51
56
|
# thus only available as attributes on the singleton
|
|
@@ -70,6 +75,18 @@ module Cosmos
|
|
|
70
75
|
# subscribe_packet_data is called. This ID must be used in the
|
|
71
76
|
# packet_data_queues hash to access the queue.
|
|
72
77
|
attr_accessor :next_packet_data_queue_id
|
|
78
|
+
# @return [Mutex] Synchronization object around server messages
|
|
79
|
+
attr_reader :server_message_queue_mutex
|
|
80
|
+
# @return [Hash<Integer, Array<Queue, Integer>>] The server message queues
|
|
81
|
+
# hashed by id. Returns an array containing the queue followed by the
|
|
82
|
+
# queue size.
|
|
83
|
+
attr_reader :server_message_queues
|
|
84
|
+
# @return [Integer] The next server message queue id when
|
|
85
|
+
# subscribe_server_messages is called. This ID must be used in the
|
|
86
|
+
# server_message_queues hash to access the queue.
|
|
87
|
+
attr_accessor :next_server_message_queue_id
|
|
88
|
+
# @return [Boolean] Whether the server was created in disconnect mode
|
|
89
|
+
attr_reader :disconnect
|
|
73
90
|
|
|
74
91
|
# The default configuration file name
|
|
75
92
|
DEFAULT_CONFIG_FILE = File.join(Cosmos::USERPATH, 'config', 'tools', 'cmd_tlm_server', 'cmd_tlm_server.txt')
|
|
@@ -79,6 +96,9 @@ module Cosmos
|
|
|
79
96
|
# The maximum number of packets that are queued. Used when subscribing to
|
|
80
97
|
# packet data.
|
|
81
98
|
DEFAULT_PACKET_DATA_QUEUE_SIZE = 1000
|
|
99
|
+
# The maximum number of server messages that are queued. Used when subscribing to
|
|
100
|
+
# server messages.
|
|
101
|
+
DEFAULT_SERVER_MESSAGES_QUEUE_SIZE = 1000
|
|
82
102
|
|
|
83
103
|
@@instance = nil
|
|
84
104
|
@@meta_callback = nil
|
|
@@ -93,7 +113,8 @@ module Cosmos
|
|
|
93
113
|
@@meta_callback = meta_callback
|
|
94
114
|
end
|
|
95
115
|
|
|
96
|
-
# Constructor for a CmdTlmServer
|
|
116
|
+
# Constructor for a CmdTlmServer. Initializes all internal state and
|
|
117
|
+
# starts up the sever
|
|
97
118
|
#
|
|
98
119
|
# @param config_file [String] The name of the server configuration file
|
|
99
120
|
# which must be in the config/tools/cmd_tlm_server directory.
|
|
@@ -104,13 +125,16 @@ module Cosmos
|
|
|
104
125
|
# stand-alone mode which does not actually use the interfaces to send and
|
|
105
126
|
# receive data. This is useful for testing scripts when actual hardware
|
|
106
127
|
# is not available.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
128
|
+
# @param mode [Symbol] :CMD_TLM_SERVER or :REPLAY - Defines overall mode
|
|
129
|
+
def initialize(
|
|
130
|
+
config_file = DEFAULT_CONFIG_FILE,
|
|
131
|
+
production = false,
|
|
132
|
+
disconnect = false,
|
|
133
|
+
mode = :CMD_TLM_SERVER)
|
|
134
|
+
|
|
111
135
|
@@instance = self
|
|
112
136
|
@packet_logging = nil # Removes warnings
|
|
113
|
-
@
|
|
137
|
+
@mode = mode
|
|
114
138
|
|
|
115
139
|
super() # For Api
|
|
116
140
|
|
|
@@ -121,10 +145,12 @@ module Cosmos
|
|
|
121
145
|
@limits_event_queue_mutex = Mutex.new
|
|
122
146
|
@limits_event_queues = {}
|
|
123
147
|
@next_limits_event_queue_id = 1
|
|
124
|
-
|
|
125
148
|
@packet_data_queue_mutex = Mutex.new
|
|
126
149
|
@packet_data_queues = {}
|
|
127
150
|
@next_packet_data_queue_id = 1
|
|
151
|
+
@server_message_queue_mutex = Mutex.new
|
|
152
|
+
@server_message_queues = {}
|
|
153
|
+
@next_server_message_queue_id = 1
|
|
128
154
|
|
|
129
155
|
# Process cmd_tlm_server.txt
|
|
130
156
|
@config = CmdTlmServerConfig.new(config_file)
|
|
@@ -133,8 +159,13 @@ module Cosmos
|
|
|
133
159
|
@interfaces = Interfaces.new(@config, method(:identified_packet_callback))
|
|
134
160
|
@packet_logging = PacketLogging.new(@config)
|
|
135
161
|
@routers = Routers.new(@config)
|
|
162
|
+
@replay_backend = ReplayBackend.new(@config)
|
|
136
163
|
@title = @config.title
|
|
164
|
+
if @mode != :CMD_TLM_SERVER
|
|
165
|
+
@title.gsub!("Command and Telemetry Server", "Replay")
|
|
166
|
+
end
|
|
137
167
|
@stop_callback = nil
|
|
168
|
+
@reload_callback = nil
|
|
138
169
|
|
|
139
170
|
# Set Threads to kill CTS if they throw an exception
|
|
140
171
|
Thread.abort_on_exception = true
|
|
@@ -142,113 +173,98 @@ module Cosmos
|
|
|
142
173
|
# Don't start the DRb service or the telemetry monitoring thread
|
|
143
174
|
# if we started the server in disconnect mode
|
|
144
175
|
@json_drb = nil
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if production
|
|
167
|
-
@packet_logging.start
|
|
168
|
-
@api_whitelist.delete('stop_logging')
|
|
169
|
-
@api_whitelist.delete('stop_cmd_log')
|
|
170
|
-
@api_whitelist.delete('stop_tlm_log')
|
|
171
|
-
@interfaces.all.each do |name, interface|
|
|
172
|
-
interface.disable_disconnect = true
|
|
173
|
-
end
|
|
174
|
-
@routers.all.each do |name, interface|
|
|
175
|
-
interface.disable_disconnect = true
|
|
176
|
+
unless @disconnect
|
|
177
|
+
System.telemetry # Make sure definitions are loaded by starting anything
|
|
178
|
+
|
|
179
|
+
@@meta_callback.call() if @@meta_callback and @config.metadata
|
|
180
|
+
|
|
181
|
+
# Start DRb with access control
|
|
182
|
+
@json_drb = JsonDRb.new
|
|
183
|
+
@json_drb.acl = System.acl if System.acl
|
|
184
|
+
|
|
185
|
+
# In production we start logging and don't allow the user to stop it
|
|
186
|
+
# We also disallow setting telemetry and disconnecting from interfaces
|
|
187
|
+
if production
|
|
188
|
+
@api_whitelist.delete('stop_logging')
|
|
189
|
+
@api_whitelist.delete('stop_cmd_log')
|
|
190
|
+
@api_whitelist.delete('stop_tlm_log')
|
|
191
|
+
@interfaces.all.each do |name, interface|
|
|
192
|
+
interface.disable_disconnect = true
|
|
193
|
+
end
|
|
194
|
+
@routers.all.each do |name, interface|
|
|
195
|
+
interface.disable_disconnect = true
|
|
196
|
+
end
|
|
176
197
|
end
|
|
177
|
-
|
|
178
|
-
@json_drb.method_whitelist = @api_whitelist
|
|
179
|
-
begin
|
|
180
|
-
@json_drb.start_service(System.listen_hosts['CTS_API'], System.ports['CTS_API'], self)
|
|
181
|
-
rescue Exception
|
|
182
|
-
# Call packet_logging shutdown here to explicitly kill the logging
|
|
183
|
-
# threads since this CTS is not going to launch
|
|
184
|
-
@packet_logging.shutdown
|
|
185
|
-
raise FatalError.new("Error starting JsonDRb on port #{System.ports['CTS_API']}.\nPerhaps a Command and Telemetry Server is already running?")
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
@routers.add_preidentified('PREIDENTIFIED_ROUTER', System.instance.ports['CTS_PREIDENTIFIED'])
|
|
189
|
-
@routers.add_cmd_preidentified('PREIDENTIFIED_CMD_ROUTER', System.instance.ports['CTS_CMD_ROUTER'])
|
|
190
|
-
System.telemetry.limits_change_callback = method(:limits_change_callback)
|
|
191
|
-
@interfaces.start
|
|
192
|
-
@routers.start
|
|
193
|
-
@background_tasks.start_all
|
|
194
|
-
|
|
195
|
-
# Start staleness monitor thread
|
|
196
|
-
@sleeper = Sleeper.new
|
|
197
|
-
@staleness_monitor_thread = Thread.new do
|
|
198
|
+
@json_drb.method_whitelist = @api_whitelist
|
|
198
199
|
begin
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
#
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
pkt_name = [packet.target_name, packet.packet_name]
|
|
213
|
-
stale << pkt_name
|
|
214
|
-
post_limits_event(:STALE_PACKET, pkt_name) unless prev_stale.include?(pkt_name)
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
# Send :STALE_PACKET_RCVD events for all packets that were stale
|
|
218
|
-
# but are no longer stale.
|
|
219
|
-
prev_stale.each do |pkt_name|
|
|
220
|
-
post_limits_event(:STALE_PACKET_RCVD, pkt_name) unless stale.include?(pkt_name)
|
|
221
|
-
end
|
|
222
|
-
prev_stale = stale.dup
|
|
223
|
-
|
|
224
|
-
broken = @sleeper.sleep(10)
|
|
225
|
-
break if broken
|
|
200
|
+
if @mode == :CMD_TLM_SERVER
|
|
201
|
+
@json_drb.start_service(System.listen_hosts['CTS_API'], System.ports['CTS_API'], self)
|
|
202
|
+
else
|
|
203
|
+
@json_drb.start_service(System.listen_hosts['REPLAY_API'], System.ports['REPLAY_API'], self)
|
|
204
|
+
end
|
|
205
|
+
rescue Exception
|
|
206
|
+
# Call packet_logging shutdown here to explicitly kill the logging
|
|
207
|
+
# threads since this CTS is not going to launch
|
|
208
|
+
@packet_logging.shutdown
|
|
209
|
+
if @mode == :CMD_TLM_SERVER
|
|
210
|
+
raise FatalError.new("Error starting JsonDRb on port #{System.ports['CTS_API']}.\nPerhaps a Command and Telemetry Server is already running?")
|
|
211
|
+
else
|
|
212
|
+
raise FatalError.new("Error starting JsonDRb on port #{System.ports['REPLAY_API']}.\nPerhaps another Replay is already running?")
|
|
226
213
|
end
|
|
227
|
-
rescue Exception => err
|
|
228
|
-
Logger.fatal "Staleness Monitor thread unexpectedly died"
|
|
229
|
-
Cosmos.handle_fatal_exception(err)
|
|
230
214
|
end
|
|
231
|
-
|
|
232
|
-
|
|
215
|
+
|
|
216
|
+
if @mode == :CMD_TLM_SERVER
|
|
217
|
+
@routers.add_preidentified('PREIDENTIFIED_ROUTER', System.ports['CTS_PREIDENTIFIED'])
|
|
218
|
+
@routers.add_cmd_preidentified('PREIDENTIFIED_CMD_ROUTER', System.ports['CTS_CMD_ROUTER'])
|
|
219
|
+
else
|
|
220
|
+
@routers.all.clear
|
|
221
|
+
@routers.add_preidentified('PREIDENTIFIED_ROUTER', System.ports['REPLAY_PREIDENTIFIED'])
|
|
222
|
+
@routers.add_cmd_preidentified('PREIDENTIFIED_CMD_ROUTER', System.ports['REPLAY_CMD_ROUTER'])
|
|
223
|
+
end
|
|
224
|
+
System.telemetry.limits_change_callback = method(:limits_change_callback)
|
|
225
|
+
@routers.start
|
|
226
|
+
|
|
227
|
+
start(production)
|
|
228
|
+
end
|
|
229
|
+
end # end def initialize
|
|
233
230
|
|
|
234
231
|
# Properly shuts down the command and telemetry server by stoping the
|
|
235
232
|
# JSON-RPC server, background tasks, routers, and interfaces. Also kills
|
|
236
|
-
# the packet staleness monitor thread.
|
|
233
|
+
# the packet staleness monitor thread. This is final and the server cannot be
|
|
234
|
+
# restarted, it must be recreated
|
|
237
235
|
def stop
|
|
238
|
-
#
|
|
239
|
-
@
|
|
236
|
+
# Break long pollers
|
|
237
|
+
@limits_event_queues.dup.each do |id, data|
|
|
238
|
+
queue, queue_size = @limits_event_queues.delete(id)
|
|
239
|
+
queue << nil if queue
|
|
240
|
+
end
|
|
240
241
|
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
@server_message_queues.dup.each do |id, data|
|
|
243
|
+
queue, queue_size = @server_message_queues.delete(id)
|
|
244
|
+
queue << nil if queue
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
@packet_data_queues.dup.each do |id, data|
|
|
248
|
+
queue, packets, queue_size = @packet_data_queues.delete(id)
|
|
249
|
+
queue << nil if queue
|
|
250
|
+
end
|
|
243
251
|
|
|
244
|
-
|
|
252
|
+
# Shutdown DRb
|
|
253
|
+
@json_drb.stop_service if @json_drb
|
|
245
254
|
@routers.stop
|
|
246
|
-
|
|
247
|
-
@
|
|
255
|
+
|
|
256
|
+
if @mode == :CMD_TLM_SERVER
|
|
257
|
+
# Shutdown staleness monitor thread
|
|
258
|
+
Cosmos.kill_thread(self, @staleness_monitor_thread)
|
|
259
|
+
|
|
260
|
+
@background_tasks.stop_all
|
|
261
|
+
@interfaces.stop
|
|
262
|
+
@packet_logging.shutdown
|
|
263
|
+
else
|
|
264
|
+
@replay_backend.shutdown
|
|
265
|
+
end
|
|
248
266
|
@stop_callback.call if @stop_callback
|
|
249
267
|
@message_log.stop if @message_log
|
|
250
|
-
|
|
251
|
-
@json_drb = nil
|
|
252
268
|
end
|
|
253
269
|
|
|
254
270
|
# Set a stop callback
|
|
@@ -256,6 +272,21 @@ module Cosmos
|
|
|
256
272
|
@stop_callback = stop_callback
|
|
257
273
|
end
|
|
258
274
|
|
|
275
|
+
# Reload the default configuration
|
|
276
|
+
def reload
|
|
277
|
+
@replay_backend.shutdown if @mode != :CMD_TLM_SERVER
|
|
278
|
+
if @reload_callback
|
|
279
|
+
@reload_callback.call(false)
|
|
280
|
+
else
|
|
281
|
+
System.reset
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Set a reload callback
|
|
286
|
+
def reload_callback= (reload_callback)
|
|
287
|
+
@reload_callback = reload_callback
|
|
288
|
+
end
|
|
289
|
+
|
|
259
290
|
# Gracefully kill the staleness monitor thread
|
|
260
291
|
def graceful_kill
|
|
261
292
|
@sleeper.cancel
|
|
@@ -289,13 +320,15 @@ module Cosmos
|
|
|
289
320
|
|
|
290
321
|
post_limits_event(:LIMITS_CHANGE, [packet.target_name, packet.packet_name, item.name, old_limits_state, item.limits.state])
|
|
291
322
|
|
|
292
|
-
if
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
323
|
+
if @mode == :CMD_TLM_SERVER
|
|
324
|
+
if item.limits.response
|
|
325
|
+
begin
|
|
326
|
+
item.limits.response.call(packet, item, old_limits_state)
|
|
327
|
+
rescue Exception => err
|
|
328
|
+
Logger.error "#{packet.target_name} #{packet.packet_name} #{item.name} Limits Response Exception!"
|
|
329
|
+
Logger.error "Called with old_state = #{old_limits_state}, new_state = #{item.limits.state}"
|
|
330
|
+
Logger.error err.formatted
|
|
331
|
+
end
|
|
299
332
|
end
|
|
300
333
|
end
|
|
301
334
|
end
|
|
@@ -352,6 +385,10 @@ module Cosmos
|
|
|
352
385
|
# @return [Integer] The queue ID returned from the CmdTlmServer. Use this
|
|
353
386
|
# ID when calling {#get_limits_event} and {#unsubscribe_limits_events}.
|
|
354
387
|
def self.subscribe_limits_events(queue_size = DEFAULT_LIMITS_EVENT_QUEUE_SIZE)
|
|
388
|
+
unless queue_size.is_a? Integer and queue_size > 0
|
|
389
|
+
raise ArgumentError, "Invalid queue size for subscribe_limits_events: #{queue_size}"
|
|
390
|
+
end
|
|
391
|
+
|
|
355
392
|
id = nil
|
|
356
393
|
@@instance.limits_event_queue_mutex.synchronize do
|
|
357
394
|
id = @@instance.next_limits_event_queue_id
|
|
@@ -461,12 +498,22 @@ module Cosmos
|
|
|
461
498
|
upcase_packets = []
|
|
462
499
|
|
|
463
500
|
# Upper case packet names
|
|
501
|
+
need_meta = false
|
|
464
502
|
packets.length.times do |index|
|
|
465
503
|
upcase_packets << []
|
|
466
504
|
upcase_packets[index][0] = packets[index][0].upcase
|
|
467
505
|
upcase_packets[index][1] = packets[index][1].upcase
|
|
506
|
+
|
|
468
507
|
# Get the packet to ensure it exists
|
|
469
|
-
@@instance.
|
|
508
|
+
if @@instance.disconnect
|
|
509
|
+
@last_subscribed_packet = System.telemetry.packet(upcase_packets[index][0], upcase_packets[index][1])
|
|
510
|
+
else
|
|
511
|
+
@@instance.get_tlm_packet(upcase_packets[index][0], upcase_packets[index][1])
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
if upcase_packets[index][0] == 'SYSTEM' and upcase_packets[index][1] == 'META'
|
|
515
|
+
need_meta = true
|
|
516
|
+
end
|
|
470
517
|
end
|
|
471
518
|
|
|
472
519
|
@@instance.packet_data_queue_mutex.synchronize do
|
|
@@ -474,6 +521,15 @@ module Cosmos
|
|
|
474
521
|
@@instance.packet_data_queues[id] =
|
|
475
522
|
[Queue.new, upcase_packets, queue_size]
|
|
476
523
|
@@instance.next_packet_data_queue_id += 1
|
|
524
|
+
|
|
525
|
+
# Send the current meta packet first if requested
|
|
526
|
+
if need_meta
|
|
527
|
+
packet = System.telemetry.packet('SYSTEM', 'META')
|
|
528
|
+
received_time = packet.received_time
|
|
529
|
+
received_time ||= Time.now.sys
|
|
530
|
+
@@instance.packet_data_queues[id][0] << [packet.buffer, 'SYSTEM', 'META',
|
|
531
|
+
received_time.tv_sec, received_time.tv_usec, packet.received_count]
|
|
532
|
+
end
|
|
477
533
|
end
|
|
478
534
|
return id
|
|
479
535
|
end
|
|
@@ -509,17 +565,117 @@ module Cosmos
|
|
|
509
565
|
queue, _, _ = @@instance.packet_data_queues[id]
|
|
510
566
|
end
|
|
511
567
|
if queue
|
|
512
|
-
|
|
568
|
+
if @@instance.disconnect
|
|
569
|
+
begin
|
|
570
|
+
return queue.pop(true)
|
|
571
|
+
rescue ThreadError
|
|
572
|
+
received_time ||= Time.now.sys
|
|
573
|
+
return [@last_subscribed_packet.buffer, @last_subscribed_packet.target_name,
|
|
574
|
+
@last_subscribed_packet.packet_name, received_time.tv_sec, received_time.tv_usec, @last_subscribed_packet.received_count]
|
|
575
|
+
end
|
|
576
|
+
else
|
|
577
|
+
return queue.pop(non_block)
|
|
578
|
+
end
|
|
513
579
|
else
|
|
514
580
|
raise "Packet data queue with id #{id} not found"
|
|
515
581
|
end
|
|
516
582
|
end
|
|
517
583
|
|
|
584
|
+
# Post a server message to all subscribed server message listeners.
|
|
585
|
+
# Messages are formatted as [Text, Color], e.g. ["Msg1","RED"]
|
|
586
|
+
#
|
|
587
|
+
# @param message [Array<String, String>] Server message
|
|
588
|
+
def post_server_message(message)
|
|
589
|
+
if @server_message_queues.length > 0
|
|
590
|
+
queues_to_drop = []
|
|
591
|
+
|
|
592
|
+
@server_message_queue_mutex.synchronize do
|
|
593
|
+
# Post event to active queues
|
|
594
|
+
@server_message_queues.each do |id, data|
|
|
595
|
+
queue = data[0]
|
|
596
|
+
queue_size = data[1]
|
|
597
|
+
queue << message
|
|
598
|
+
if queue.length > queue_size
|
|
599
|
+
# Drop queue
|
|
600
|
+
queues_to_drop << id
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Drop queues which are not being serviced
|
|
605
|
+
queues_to_drop.each do |id|
|
|
606
|
+
# Remove the queue to stop servicing it. Nil is added to unblock any client threads
|
|
607
|
+
# that might otherwise be left blocking forever for something on the queue
|
|
608
|
+
queue, queue_size = @server_message_queues.delete(id)
|
|
609
|
+
queue << nil if queue
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
# Create a queue on the CmdTlmServer that gets populated with every message
|
|
616
|
+
# in the system.
|
|
617
|
+
#
|
|
618
|
+
# @param queue_size [Integer] The number of server messages to accumulate
|
|
619
|
+
# before the queue will be dropped due to inactivity.
|
|
620
|
+
# @return [Integer] The queue ID returned from the CmdTlmServer. Use this
|
|
621
|
+
# ID when calling {#get_server_message} and {#unsubscribe_server_messages}.
|
|
622
|
+
def self.subscribe_server_messages(queue_size = DEFAULT_SERVER_MESSAGES_QUEUE_SIZE)
|
|
623
|
+
unless queue_size.is_a? Integer and queue_size > 0
|
|
624
|
+
raise ArgumentError, "Invalid queue size for subscribe_server_messages: #{queue_size}"
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
id = nil
|
|
628
|
+
@@instance.server_message_queue_mutex.synchronize do
|
|
629
|
+
id = @@instance.next_server_message_queue_id
|
|
630
|
+
@@instance.server_message_queues[id] = [Queue.new, queue_size]
|
|
631
|
+
@@instance.next_server_message_queue_id += 1
|
|
632
|
+
end
|
|
633
|
+
return id
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
# Unsubscribe from being notified for every server message in the system.
|
|
637
|
+
# This deletes the queue and further calls to {#get_server_message} will
|
|
638
|
+
# raise an exception.
|
|
639
|
+
#
|
|
640
|
+
# @param id [Integer] The queue ID received from calling
|
|
641
|
+
# {#subscribe_server_messages}
|
|
642
|
+
def self.unsubscribe_server_messages(id)
|
|
643
|
+
queue = nil
|
|
644
|
+
@@instance.server_message_queue_mutex.synchronize do
|
|
645
|
+
# Remove the queue to stop servicing it. Nil is added to unblock any client threads
|
|
646
|
+
# that might otherwise be left blocking forever for something on the queue
|
|
647
|
+
queue, queue_size = @@instance.server_message_queues.delete(id)
|
|
648
|
+
queue << nil if queue
|
|
649
|
+
end
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
# Get a server message from the queue created by {#subscribe_server_messages}.
|
|
653
|
+
#
|
|
654
|
+
# Each server message consists of a String
|
|
655
|
+
#
|
|
656
|
+
# @param id [Integer] The queue ID received from calling
|
|
657
|
+
# {#subscribe_server_messages}
|
|
658
|
+
# @param non_block [Boolean] Whether to wait on the queue for the next
|
|
659
|
+
# server message before returning. Default is to block waiting for the next
|
|
660
|
+
# message. NOTE: If you pass true and there is no data on the queue, a
|
|
661
|
+
# ThreadError exception is raised.
|
|
662
|
+
def self.get_server_message(id, non_block = false)
|
|
663
|
+
queue = nil
|
|
664
|
+
@@instance.server_message_queue_mutex.synchronize do
|
|
665
|
+
queue, _ = @@instance.server_message_queues[id]
|
|
666
|
+
end
|
|
667
|
+
if queue
|
|
668
|
+
return queue.pop(non_block)
|
|
669
|
+
else
|
|
670
|
+
raise "Server message queue with id #{id} not found"
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
|
|
518
674
|
# Calls clear_counters on the System, interfaces, routers, and sets the
|
|
519
675
|
# request_count on json_drb to 0.
|
|
520
676
|
def self.clear_counters
|
|
521
677
|
System.clear_counters
|
|
522
|
-
self.instance.interfaces.clear_counters
|
|
678
|
+
self.instance.interfaces.clear_counters if self.instance.interfaces
|
|
523
679
|
self.instance.routers.clear_counters
|
|
524
680
|
self.instance.json_drb.request_count = 0
|
|
525
681
|
end
|
|
@@ -533,5 +689,67 @@ module Cosmos
|
|
|
533
689
|
packet.check_limits(System.limits_set)
|
|
534
690
|
post_packet(packet)
|
|
535
691
|
end
|
|
692
|
+
|
|
693
|
+
private
|
|
694
|
+
|
|
695
|
+
# Start up the system by starting the JSON-RPC server, interfaces, routers,
|
|
696
|
+
# and background tasks. Starts a thread to monitor all packets for
|
|
697
|
+
# staleness so other tools (such as Packet Viewer or Telemetry Viewer) can
|
|
698
|
+
# react accordingly.
|
|
699
|
+
#
|
|
700
|
+
# This method is shoudl only called by initialize which is why it is private
|
|
701
|
+
#
|
|
702
|
+
# @param start_packet_logging [Boolean] Whether to start logging data or not
|
|
703
|
+
def start(start_packet_logging = false)
|
|
704
|
+
if @mode == :CMD_TLM_SERVER
|
|
705
|
+
@replay_backend = nil # Remove access to Replay
|
|
706
|
+
@message_log = MessageLog.new('server')
|
|
707
|
+
@packet_logging.start if start_packet_logging
|
|
708
|
+
@interfaces.start
|
|
709
|
+
@background_tasks.start_all
|
|
710
|
+
|
|
711
|
+
# Start staleness monitor thread
|
|
712
|
+
@sleeper = Sleeper.new
|
|
713
|
+
@staleness_monitor_thread = Thread.new do
|
|
714
|
+
begin
|
|
715
|
+
stale = []
|
|
716
|
+
prev_stale = []
|
|
717
|
+
while true
|
|
718
|
+
# The check_stale method drives System.telemetry to iterate through
|
|
719
|
+
# the packets and mark them stale as necessary.
|
|
720
|
+
System.telemetry.check_stale
|
|
721
|
+
|
|
722
|
+
# Get all stale packets that include limits items.
|
|
723
|
+
stale_pkts = System.telemetry.stale(true)
|
|
724
|
+
|
|
725
|
+
# Send :STALE_PACKET events for all newly stale packets.
|
|
726
|
+
stale = []
|
|
727
|
+
stale_pkts.each do |packet|
|
|
728
|
+
pkt_name = [packet.target_name, packet.packet_name]
|
|
729
|
+
stale << pkt_name
|
|
730
|
+
post_limits_event(:STALE_PACKET, pkt_name) unless prev_stale.include?(pkt_name)
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
# Send :STALE_PACKET_RCVD events for all packets that were stale
|
|
734
|
+
# but are no longer stale.
|
|
735
|
+
prev_stale.each do |pkt_name|
|
|
736
|
+
post_limits_event(:STALE_PACKET_RCVD, pkt_name) unless stale.include?(pkt_name)
|
|
737
|
+
end
|
|
738
|
+
prev_stale = stale.dup
|
|
739
|
+
|
|
740
|
+
broken = @sleeper.sleep(10)
|
|
741
|
+
break if broken
|
|
742
|
+
end
|
|
743
|
+
rescue Exception => err
|
|
744
|
+
Logger.fatal "Staleness Monitor thread unexpectedly died"
|
|
745
|
+
Cosmos.handle_fatal_exception(err)
|
|
746
|
+
end
|
|
747
|
+
end # end Thread.new
|
|
748
|
+
else
|
|
749
|
+
# Prevent access to interfaces or packet_logging
|
|
750
|
+
@interfaces = nil
|
|
751
|
+
@packet_logging = nil
|
|
752
|
+
end
|
|
753
|
+
end
|
|
536
754
|
end
|
|
537
755
|
end
|