cosmos 3.1.2 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|