cosmos 3.1.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/Manifest.txt +17 -1
- data/autohotkey/tools/test_runner2.ahk +1 -0
- data/autohotkey/tools/tlm_grapher.ahk +13 -1
- data/data/crc.txt +39 -30
- data/demo/config/data/crc.txt +3 -3
- data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +3 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +7 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +6 -1
- data/lib/cosmos.rb +2 -2
- data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -5
- data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +0 -7
- data/lib/cosmos/gui/line_graph/overview_graph.rb +12 -2
- data/lib/cosmos/gui/utilities/script_module_gui.rb +11 -3
- data/lib/cosmos/interfaces/interface.rb +12 -0
- data/lib/cosmos/interfaces/stream_interface.rb +1 -21
- data/lib/cosmos/interfaces/tcpip_server_interface.rb +10 -0
- data/lib/cosmos/io/json_drb_object.rb +75 -56
- data/lib/cosmos/io/tcpip_server.rb +1 -11
- data/lib/cosmos/packet_logs.rb +1 -0
- data/lib/cosmos/packet_logs/ccsds_log_reader.rb +103 -0
- data/lib/cosmos/packets/packet.rb +70 -1
- data/lib/cosmos/packets/packet_config.rb +59 -611
- data/lib/cosmos/packets/parsers/format_string_parser.rb +58 -0
- data/lib/cosmos/packets/parsers/limits_parser.rb +146 -0
- data/lib/cosmos/packets/parsers/limits_response_parser.rb +52 -0
- data/lib/cosmos/packets/parsers/macro_parser.rb +116 -0
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +215 -0
- data/lib/cosmos/packets/parsers/packet_parser.rb +123 -0
- data/lib/cosmos/packets/parsers/processor_parser.rb +63 -0
- data/lib/cosmos/packets/parsers/state_parser.rb +116 -0
- data/lib/cosmos/packets/structure.rb +59 -22
- data/lib/cosmos/packets/structure_item.rb +1 -1
- data/lib/cosmos/script/script.rb +4 -5
- data/lib/cosmos/streams/serial_stream.rb +5 -0
- data/lib/cosmos/streams/stream.rb +8 -2
- data/lib/cosmos/streams/stream_protocol.rb +1 -0
- data/lib/cosmos/streams/tcpip_client_stream.rb +37 -7
- data/lib/cosmos/streams/tcpip_socket_stream.rb +9 -6
- data/lib/cosmos/system/target.rb +3 -6
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +57 -48
- data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +7 -3
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +1 -1
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +7 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +1 -2
- data/lib/cosmos/top_level.rb +22 -11
- data/lib/cosmos/utilities/message_log.rb +14 -9
- data/lib/cosmos/version.rb +5 -5
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +16 -16
- data/spec/interfaces/linc_interface_spec.rb +3 -0
- data/spec/interfaces/tcpip_client_interface_spec.rb +1 -0
- data/spec/interfaces/tcpip_server_interface_spec.rb +9 -0
- data/spec/io/json_drb_object_spec.rb +1 -1
- data/spec/io/serial_driver_spec.rb +0 -1
- data/spec/packet_logs/packet_log_writer_spec.rb +5 -3
- data/spec/packets/packet_config_spec.rb +22 -837
- data/spec/packets/packet_item_spec.rb +10 -10
- data/spec/packets/packet_spec.rb +239 -1
- data/spec/packets/parsers/format_string_parser_spec.rb +122 -0
- data/spec/packets/parsers/limits_parser_spec.rb +282 -0
- data/spec/packets/parsers/limits_response_parser_spec.rb +149 -0
- data/spec/packets/parsers/macro_parser_spec.rb +184 -0
- data/spec/packets/parsers/packet_item_parser_spec.rb +306 -0
- data/spec/packets/parsers/packet_parser_spec.rb +99 -0
- data/spec/packets/parsers/processor_parser_spec.rb +114 -0
- data/spec/packets/parsers/state_parser_spec.rb +156 -0
- data/spec/packets/structure_item_spec.rb +14 -14
- data/spec/packets/structure_spec.rb +162 -16
- data/spec/streams/fixed_stream_protocol_spec.rb +7 -4
- data/spec/streams/length_stream_protocol_spec.rb +3 -0
- data/spec/streams/preidentified_stream_protocol_spec.rb +3 -0
- data/spec/streams/serial_stream_spec.rb +12 -0
- data/spec/streams/stream_protocol_spec.rb +14 -0
- data/spec/streams/stream_spec.rb +1 -0
- data/spec/streams/tcpip_client_stream_spec.rb +3 -0
- data/spec/streams/tcpip_socket_stream_spec.rb +15 -3
- data/spec/streams/template_stream_protocol_spec.rb +5 -0
- data/spec/streams/terminated_stream_protocol_spec.rb +4 -0
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +21 -1
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +1 -1
- data/spec/tools/cmd_tlm_server/interfaces_spec.rb +1 -1
- metadata +19 -3
|
@@ -116,13 +116,6 @@ module Cosmos
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def value_update_timeout
|
|
119
|
-
# Check to see that the server is still running. If the user shut down
|
|
120
|
-
# the underlying tool (like PacketViewer for example) the $cmd_tlm_server
|
|
121
|
-
# will be nil.
|
|
122
|
-
unless $cmd_tlm_server
|
|
123
|
-
@timer.stop
|
|
124
|
-
return
|
|
125
|
-
end
|
|
126
119
|
begin
|
|
127
120
|
# Gather updated values
|
|
128
121
|
values, limits_states, limits_settings, limits_set = get_tlm_values(@item_array, VALUE_TYPES)
|
|
@@ -111,12 +111,12 @@ module Cosmos
|
|
|
111
111
|
temp_max = (@window_max_start + (x - @drag_start_x))
|
|
112
112
|
|
|
113
113
|
# Only graph if the user hasn't dragged the window outside the graph
|
|
114
|
-
if temp_min >=
|
|
114
|
+
if temp_min >= @graph_left_x and temp_max <= @graph_right_x
|
|
115
115
|
#Now convert the graph coordinates back to the x values
|
|
116
116
|
@window_min_x = scale_graph_to_value_x(temp_min)
|
|
117
117
|
@window_max_x = scale_graph_to_value_x(temp_max)
|
|
118
118
|
else # The user dragged outside the allowable area
|
|
119
|
-
if temp_min <
|
|
119
|
+
if temp_min < @graph_left_x
|
|
120
120
|
@window_min_x = @x_min
|
|
121
121
|
@window_max_x = @x_min + @window_size
|
|
122
122
|
elsif temp_max > @graph_right_x
|
|
@@ -124,6 +124,8 @@ module Cosmos
|
|
|
124
124
|
@window_min_x = @window_max_x - @window_size
|
|
125
125
|
end
|
|
126
126
|
end
|
|
127
|
+
@window_min_x = @x_min if @window_min_x < @x_min
|
|
128
|
+
@window_max_x = @x_max if @window_max_x > @x_max
|
|
127
129
|
@redraw_needed = true
|
|
128
130
|
graph()
|
|
129
131
|
end
|
|
@@ -171,6 +173,8 @@ module Cosmos
|
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
# Update window size
|
|
176
|
+
@window_min_x = @x_min if @window_min_x < @x_min
|
|
177
|
+
@window_max_x = @x_max if @window_max_x > @x_max
|
|
174
178
|
@window_size = @window_max_x - @window_min_x
|
|
175
179
|
|
|
176
180
|
@redraw_needed = true
|
|
@@ -315,6 +319,8 @@ module Cosmos
|
|
|
315
319
|
@window_min_x = center - @window_size / 2
|
|
316
320
|
@window_max_x = center + @window_size / 2
|
|
317
321
|
end
|
|
322
|
+
@window_min_x = @x_min if @window_min_x < @x_min
|
|
323
|
+
@window_max_x = @x_max if @window_max_x > @x_max
|
|
318
324
|
@drag_window = true
|
|
319
325
|
@redraw_needed = true
|
|
320
326
|
graph()
|
|
@@ -346,6 +352,8 @@ module Cosmos
|
|
|
346
352
|
@window_min_x = @x_max - @window_size
|
|
347
353
|
@window_max_x = @x_max
|
|
348
354
|
end
|
|
355
|
+
@window_min_x = @x_min if @window_min_x < @x_min
|
|
356
|
+
@window_max_x = @x_max if @window_max_x > @x_max
|
|
349
357
|
|
|
350
358
|
@drag_window = true
|
|
351
359
|
@redraw_needed = true
|
|
@@ -427,8 +435,10 @@ module Cosmos
|
|
|
427
435
|
# The window lines are in terms of the graph x values so convert to the graph coordinate system
|
|
428
436
|
@window_left_x = scale_value_to_graph_x(@window_min_x)
|
|
429
437
|
@window_left_x = @graph_left_x if @window_left_x < @graph_left_x
|
|
438
|
+
@window_left_x = @graph_right_x if @window_left_x > @graph_right_x
|
|
430
439
|
@window_right_x = scale_value_to_graph_x(@window_max_x)
|
|
431
440
|
@window_right_x = @graph_right_x if @window_right_x > @graph_right_x
|
|
441
|
+
@window_right_x = @graph_left_x if @window_right_x < @graph_left_x
|
|
432
442
|
else # If we're not dragging the window we want to adjust the window lines automatically
|
|
433
443
|
@window_max_x = @x_max
|
|
434
444
|
|
|
@@ -21,7 +21,7 @@ module Cosmos
|
|
|
21
21
|
|
|
22
22
|
@@qt_boolean = Qt::Boolean.new
|
|
23
23
|
|
|
24
|
-
def ask_string(question, allow_blank = false)
|
|
24
|
+
def ask_string(question, allow_blank = false, password = false)
|
|
25
25
|
answer = ""
|
|
26
26
|
loop do
|
|
27
27
|
canceled = false
|
|
@@ -29,7 +29,11 @@ module Cosmos
|
|
|
29
29
|
window = nil
|
|
30
30
|
window = get_cmd_tlm_gui_window() if get_cmd_tlm_gui_window()
|
|
31
31
|
# Create a special mutable QT variable that can return what button was pressed
|
|
32
|
-
|
|
32
|
+
if password
|
|
33
|
+
answer = Qt::InputDialog::getText(window, "Ask", question, Qt::LineEdit::Password, "", @@qt_boolean)
|
|
34
|
+
else
|
|
35
|
+
answer = Qt::InputDialog::getText(window, "Ask", question, Qt::LineEdit::Normal, "", @@qt_boolean)
|
|
36
|
+
end
|
|
33
37
|
# @@qt_boolean is nil if the user presses cancel in the dialog
|
|
34
38
|
# Note that it is not actually nil, just the nil? method returns true
|
|
35
39
|
canceled = @@qt_boolean.nil?
|
|
@@ -42,7 +46,11 @@ module Cosmos
|
|
|
42
46
|
break if allow_blank or (not answer.nil? and answer.strip.length != 0)
|
|
43
47
|
end
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
if password
|
|
50
|
+
Logger.info "User responded to '#{question}'"
|
|
51
|
+
else
|
|
52
|
+
Logger.info "User entered '#{answer}' for '#{question}'"
|
|
53
|
+
end
|
|
46
54
|
return answer.to_s
|
|
47
55
|
end
|
|
48
56
|
|
|
@@ -81,6 +81,9 @@ module Cosmos
|
|
|
81
81
|
# (when used as a Router)
|
|
82
82
|
attr_accessor :interfaces
|
|
83
83
|
|
|
84
|
+
# @return [Hash<option name, option values>] Hash of options supplied to interface/router
|
|
85
|
+
attr_accessor :options
|
|
86
|
+
|
|
84
87
|
# Initialize default attribute values
|
|
85
88
|
def initialize
|
|
86
89
|
@name = self.class.to_s
|
|
@@ -104,6 +107,7 @@ module Cosmos
|
|
|
104
107
|
@read_allowed = true
|
|
105
108
|
@write_allowed = true
|
|
106
109
|
@write_raw_allowed = true
|
|
110
|
+
@options = {}
|
|
107
111
|
end
|
|
108
112
|
|
|
109
113
|
# Connects the interface to its target(s). Must be implemented by a
|
|
@@ -198,6 +202,14 @@ module Cosmos
|
|
|
198
202
|
# read_queue_size is the number of packets in the queue so don't copy
|
|
199
203
|
# write_queue_size is the number of packets in the queue so don't copy
|
|
200
204
|
other_interface.interfaces = self.interfaces.clone
|
|
205
|
+
other_interface.options = self.options.clone
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Set an interface or router specific option
|
|
209
|
+
# @param option_name name of the option
|
|
210
|
+
# @param option_values array of option values
|
|
211
|
+
def set_option(option_name, option_values)
|
|
212
|
+
@options[option_name.upcase] = option_values.clone
|
|
201
213
|
end
|
|
202
214
|
|
|
203
215
|
# This method is called by the CmdTlmServer after each read packet is
|
|
@@ -34,27 +34,7 @@ module Cosmos
|
|
|
34
34
|
super()
|
|
35
35
|
|
|
36
36
|
stream_protocol_class = stream_protocol_type.to_s.capitalize << 'StreamProtocol'
|
|
37
|
-
klass = stream_protocol_class.
|
|
38
|
-
unless klass
|
|
39
|
-
begin
|
|
40
|
-
require stream_protocol_class.class_name_to_filename
|
|
41
|
-
# If the stream protocol doesn't exist require will throw a LoadError
|
|
42
|
-
rescue LoadError => err
|
|
43
|
-
msg = "Unable to require " \
|
|
44
|
-
"#{stream_protocol_class.class_name_to_filename} due to #{err.message}. " \
|
|
45
|
-
"Ensure #{stream_protocol_class.class_name_to_filename} "\
|
|
46
|
-
"is in the COSMOS lib directory."
|
|
47
|
-
Logger.instance.error msg
|
|
48
|
-
raise msg
|
|
49
|
-
# If the stream protocol exists but has problems we rescue those here
|
|
50
|
-
rescue => err
|
|
51
|
-
msg = "Unable to require " \
|
|
52
|
-
"#{stream_protocol_class.class_name_to_filename} due to #{err.message}."
|
|
53
|
-
Logger.instance.error msg
|
|
54
|
-
raise msg
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
37
|
+
klass = Cosmos.require_class(stream_protocol_class.class_name_to_filename)
|
|
58
38
|
@stream_protocol = klass.new(*stream_protocol_args)
|
|
59
39
|
@stream_protocol.interface = self
|
|
60
40
|
end
|
|
@@ -149,6 +149,16 @@ module Cosmos
|
|
|
149
149
|
@tcpip_server.stop_raw_logging
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
+
# Supported Options
|
|
153
|
+
# LISTEN_ADDRESS - Ip address of the interface to accept connections on - Default: 0.0.0.0
|
|
154
|
+
# (see Interface#set_option)
|
|
155
|
+
def set_option(option_name, option_values)
|
|
156
|
+
super(option_name, option_values)
|
|
157
|
+
if option_name.upcase == 'LISTEN_ADDRESS'
|
|
158
|
+
@tcpip_server.listen_address = option_values[0]
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
152
162
|
end # class TcpipServerInterface
|
|
153
163
|
|
|
154
164
|
end # module Cosmos
|
|
@@ -33,7 +33,7 @@ module Cosmos
|
|
|
33
33
|
# @param hostname [String] The name of the machine which has started
|
|
34
34
|
# the JSON service
|
|
35
35
|
# @param port [Integer] The port number of the JSON service
|
|
36
|
-
def initialize(hostname, port)
|
|
36
|
+
def initialize(hostname, port, connect_timeout = 1.0)
|
|
37
37
|
hostname = '127.0.0.1' if (hostname.to_s.upcase == 'LOCALHOST')
|
|
38
38
|
begin
|
|
39
39
|
@addr = Socket.pack_sockaddr_in(port, hostname)
|
|
@@ -50,11 +50,21 @@ module Cosmos
|
|
|
50
50
|
@socket = nil
|
|
51
51
|
@id = 0
|
|
52
52
|
@request_in_progress = false
|
|
53
|
+
@connect_timeout = connect_timeout
|
|
54
|
+
@connect_timeout = @connect_timeout.to_f if @connect_timeout
|
|
55
|
+
@shutdown = false
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
# Disconnects from the JSON server
|
|
56
59
|
def disconnect
|
|
57
|
-
|
|
60
|
+
socket = @socket
|
|
61
|
+
socket.close if socket and !socket.closed?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Permanently disconnects from the JSON server
|
|
65
|
+
def shutdown
|
|
66
|
+
@shutdown = true
|
|
67
|
+
disconnect()
|
|
58
68
|
end
|
|
59
69
|
|
|
60
70
|
# Forwards all method calls to the remote service.
|
|
@@ -66,70 +76,79 @@ module Cosmos
|
|
|
66
76
|
# protocol a DRb::DRbConnError exception is raised.
|
|
67
77
|
def method_missing(method_name, *method_params)
|
|
68
78
|
@mutex.synchronize do
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
raise DRb::DRbConnError, "Shutdown" if @shutdown
|
|
80
|
+
if !@socket or @socket.closed? or @request_in_progress
|
|
81
|
+
if @request_in_progress
|
|
82
|
+
disconnect()
|
|
83
|
+
@socket = nil
|
|
84
|
+
@request_in_progress = false
|
|
85
|
+
end
|
|
86
|
+
begin
|
|
87
|
+
addr = Socket.pack_sockaddr_in(@port, @hostname)
|
|
88
|
+
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
|
89
|
+
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
77
90
|
begin
|
|
78
|
-
@socket
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
@socket.connect_nonblock(addr)
|
|
92
|
+
rescue IO::WaitWritable
|
|
93
|
+
begin
|
|
94
|
+
_, sockets, _ = IO.select(nil, [@socket], nil, @connect_timeout) # wait 3-way handshake completion
|
|
95
|
+
rescue Errno::ENOTSOCK
|
|
96
|
+
disconnect()
|
|
97
|
+
@socket = nil
|
|
98
|
+
raise "Connect canceled"
|
|
99
|
+
end
|
|
100
|
+
if sockets and !sockets.empty?
|
|
101
|
+
begin
|
|
102
|
+
@socket.connect_nonblock(addr) # check connection failure
|
|
103
|
+
rescue Errno::EISCONN
|
|
104
|
+
end
|
|
105
|
+
else
|
|
106
|
+
disconnect()
|
|
107
|
+
@socket = nil
|
|
108
|
+
raise "Connect timeout"
|
|
109
|
+
end
|
|
82
110
|
end
|
|
111
|
+
rescue => e
|
|
112
|
+
raise DRb::DRbConnError, e.message
|
|
83
113
|
end
|
|
114
|
+
end
|
|
84
115
|
|
|
85
|
-
|
|
86
|
-
|
|
116
|
+
request = JsonRpcRequest.new(method_name, method_params, @id)
|
|
117
|
+
@id += 1
|
|
87
118
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
next
|
|
104
|
-
else
|
|
105
|
-
raise DRb::DRbConnError, e.message, e.backtrace
|
|
106
|
-
end
|
|
107
|
-
end
|
|
119
|
+
request_data = request.to_json(:allow_nan => true)
|
|
120
|
+
begin
|
|
121
|
+
@request_in_progress = true
|
|
122
|
+
STDOUT.puts "Request:\n" if JsonDRb.debug?
|
|
123
|
+
STDOUT.puts request_data if JsonDRb.debug?
|
|
124
|
+
JsonDRb.send_data(@socket, request_data)
|
|
125
|
+
response_data = JsonDRb.receive_message(@socket, '')
|
|
126
|
+
STDOUT.puts "\nResponse:\n" if JsonDRb.debug?
|
|
127
|
+
STDOUT.puts response_data if JsonDRb.debug?
|
|
128
|
+
@request_in_progress = false
|
|
129
|
+
rescue => e
|
|
130
|
+
disconnect()
|
|
131
|
+
@socket = nil
|
|
132
|
+
raise DRb::DRbConnError, e.message, e.backtrace
|
|
133
|
+
end
|
|
108
134
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
else
|
|
115
|
-
raise "JsonDRb Error (#{response.error.code}): #{response.error.message}"
|
|
116
|
-
end
|
|
135
|
+
if response_data
|
|
136
|
+
response = JsonRpcResponse.from_json(response_data)
|
|
137
|
+
if JsonRpcErrorResponse === response
|
|
138
|
+
if response.error.data
|
|
139
|
+
raise Exception.from_hash(response.error.data)
|
|
117
140
|
else
|
|
118
|
-
|
|
141
|
+
raise "JsonDRb Error (#{response.error.code}): #{response.error.message}"
|
|
119
142
|
end
|
|
120
143
|
else
|
|
121
|
-
|
|
122
|
-
@socket.close if @socket and !@socket.closed?
|
|
123
|
-
@socket = nil
|
|
124
|
-
if first_try
|
|
125
|
-
first_try = false
|
|
126
|
-
next
|
|
127
|
-
else
|
|
128
|
-
# Socket already closed by receive_message
|
|
129
|
-
raise DRb::DRbConnError, "Socket closed by server"
|
|
130
|
-
end
|
|
144
|
+
return response.result
|
|
131
145
|
end
|
|
132
|
-
|
|
146
|
+
else
|
|
147
|
+
# Socket was closed by server
|
|
148
|
+
disconnect()
|
|
149
|
+
@socket = nil
|
|
150
|
+
raise DRb::DRbConnError, "Socket closed by server"
|
|
151
|
+
end
|
|
133
152
|
end
|
|
134
153
|
end
|
|
135
154
|
end
|
|
@@ -70,17 +70,7 @@ module Cosmos
|
|
|
70
70
|
@read_timeout = @read_timeout.to_f if @read_timeout
|
|
71
71
|
|
|
72
72
|
stream_protocol_class = stream_protocol_type.to_s.capitalize << 'StreamProtocol'
|
|
73
|
-
@stream_protocol_class = stream_protocol_class.
|
|
74
|
-
unless @stream_protocol_class
|
|
75
|
-
begin
|
|
76
|
-
require "cosmos/streams/#{stream_protocol_class.class_name_to_filename}"
|
|
77
|
-
@stream_protocol_class = stream_protocol_class.to_class
|
|
78
|
-
rescue LoadError => err
|
|
79
|
-
Logger.instance.error "Unable to require #{stream_protocol_class.class_name_to_filename} due to #{err.message}. Ensure #{stream_protocol_class.class_name_to_filename} is in the COSMOS lib directory."
|
|
80
|
-
raise "Unable to require #{stream_protocol_class.class_name_to_filename} due to #{err.message}. Ensure #{stream_protocol_class.class_name_to_filename} is in the COSMOS lib directory."
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
73
|
+
@stream_protocol_class = Cosmos.require_class(stream_protocol_class.class_name_to_filename)
|
|
84
74
|
@stream_protocol_args = stream_protocol_args
|
|
85
75
|
|
|
86
76
|
@listen_sockets = []
|
data/lib/cosmos/packet_logs.rb
CHANGED
|
@@ -0,0 +1,103 @@
|
|
|
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/packet_logs/packet_log_reader'
|
|
12
|
+
require 'cosmos/ccsds/ccsds_packet'
|
|
13
|
+
|
|
14
|
+
module Cosmos
|
|
15
|
+
|
|
16
|
+
# Reads a CCSDS packet log of either commands or telemetry.
|
|
17
|
+
class CcsdsLogReader < PacketLogReader
|
|
18
|
+
|
|
19
|
+
# Length of the header on a CCSDS source packet
|
|
20
|
+
CCSDS_HEADER_LENGTH = 6
|
|
21
|
+
|
|
22
|
+
# Create a new log file reader
|
|
23
|
+
def initialize
|
|
24
|
+
super()
|
|
25
|
+
@ccsds_header = CcsdsPacket.new(nil, nil, false)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Read a packet from the log file
|
|
29
|
+
#
|
|
30
|
+
# @param identify_and_define (see #each)
|
|
31
|
+
# @return [Packet]
|
|
32
|
+
def read(identify_and_define = true)
|
|
33
|
+
# Read the CCSDS packet header
|
|
34
|
+
header = @file.read(CCSDS_HEADER_LENGTH)
|
|
35
|
+
return nil unless header and header.length == CCSDS_HEADER_LENGTH
|
|
36
|
+
@ccsds_header.buffer = header
|
|
37
|
+
|
|
38
|
+
# Extract the length field
|
|
39
|
+
length = @ccsds_header.read('CcsdsLength') + 1
|
|
40
|
+
|
|
41
|
+
# Read the remainder of the packet data
|
|
42
|
+
data = @file.read(length)
|
|
43
|
+
return nil unless data and data.length == length
|
|
44
|
+
|
|
45
|
+
# Combine into the full packet data
|
|
46
|
+
packet_data = header << data
|
|
47
|
+
|
|
48
|
+
# Determine packet time and set it as received time
|
|
49
|
+
received_time = determine_received_time(packet_data)
|
|
50
|
+
|
|
51
|
+
# Build the actual Packet object
|
|
52
|
+
if identify_and_define
|
|
53
|
+
packet = identify_and_define_packet_data(nil, nil, received_time, packet_data)
|
|
54
|
+
else
|
|
55
|
+
# Build Packet
|
|
56
|
+
packet = Packet.new(nil, nil, :BIG_ENDIAN, nil, packet_data)
|
|
57
|
+
packet.set_received_time_fast(received_time)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Return the packet
|
|
61
|
+
packet
|
|
62
|
+
rescue => err
|
|
63
|
+
close()
|
|
64
|
+
raise err
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
protected
|
|
68
|
+
|
|
69
|
+
# TODO : Add code here or in subclass to derive received time from the packet timestamp
|
|
70
|
+
# CCSDS timestamp formats and even the presence of a timestamp vary
|
|
71
|
+
def determine_received_time(packet_data)
|
|
72
|
+
nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def read_file_header
|
|
76
|
+
# Read the first CCSDS packet header
|
|
77
|
+
header = @file.read(CCSDS_HEADER_LENGTH)
|
|
78
|
+
|
|
79
|
+
if header and header.length == CCSDS_HEADER_LENGTH
|
|
80
|
+
@ccsds_header.buffer = header
|
|
81
|
+
packet_type = @ccsds_header.read('CcsdsType')
|
|
82
|
+
if packet_type == CcsdsPacket::TELEMETRY
|
|
83
|
+
@log_type = :TLM
|
|
84
|
+
else
|
|
85
|
+
@log_type = :CMD
|
|
86
|
+
end
|
|
87
|
+
@configuration_name = nil
|
|
88
|
+
@hostname = nil
|
|
89
|
+
@file_header_length = 0
|
|
90
|
+
@file.seek(0, IO::SEEK_SET)
|
|
91
|
+
System.load_configuration(nil)
|
|
92
|
+
else
|
|
93
|
+
raise "Failed to read at least #{CCSDS_HEADER_LENGTH} bytes from packet log"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def seek_to_time(time)
|
|
98
|
+
# Not supported
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end # class CcsdsLogReader
|
|
102
|
+
|
|
103
|
+
end # module Cosmos
|