cosmos 3.1.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/Manifest.txt +17 -1
  4. data/autohotkey/tools/test_runner2.ahk +1 -0
  5. data/autohotkey/tools/tlm_grapher.ahk +13 -1
  6. data/data/crc.txt +39 -30
  7. data/demo/config/data/crc.txt +3 -3
  8. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +3 -1
  9. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +7 -1
  10. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +6 -1
  11. data/lib/cosmos.rb +2 -2
  12. data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -5
  13. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +0 -7
  14. data/lib/cosmos/gui/line_graph/overview_graph.rb +12 -2
  15. data/lib/cosmos/gui/utilities/script_module_gui.rb +11 -3
  16. data/lib/cosmos/interfaces/interface.rb +12 -0
  17. data/lib/cosmos/interfaces/stream_interface.rb +1 -21
  18. data/lib/cosmos/interfaces/tcpip_server_interface.rb +10 -0
  19. data/lib/cosmos/io/json_drb_object.rb +75 -56
  20. data/lib/cosmos/io/tcpip_server.rb +1 -11
  21. data/lib/cosmos/packet_logs.rb +1 -0
  22. data/lib/cosmos/packet_logs/ccsds_log_reader.rb +103 -0
  23. data/lib/cosmos/packets/packet.rb +70 -1
  24. data/lib/cosmos/packets/packet_config.rb +59 -611
  25. data/lib/cosmos/packets/parsers/format_string_parser.rb +58 -0
  26. data/lib/cosmos/packets/parsers/limits_parser.rb +146 -0
  27. data/lib/cosmos/packets/parsers/limits_response_parser.rb +52 -0
  28. data/lib/cosmos/packets/parsers/macro_parser.rb +116 -0
  29. data/lib/cosmos/packets/parsers/packet_item_parser.rb +215 -0
  30. data/lib/cosmos/packets/parsers/packet_parser.rb +123 -0
  31. data/lib/cosmos/packets/parsers/processor_parser.rb +63 -0
  32. data/lib/cosmos/packets/parsers/state_parser.rb +116 -0
  33. data/lib/cosmos/packets/structure.rb +59 -22
  34. data/lib/cosmos/packets/structure_item.rb +1 -1
  35. data/lib/cosmos/script/script.rb +4 -5
  36. data/lib/cosmos/streams/serial_stream.rb +5 -0
  37. data/lib/cosmos/streams/stream.rb +8 -2
  38. data/lib/cosmos/streams/stream_protocol.rb +1 -0
  39. data/lib/cosmos/streams/tcpip_client_stream.rb +37 -7
  40. data/lib/cosmos/streams/tcpip_socket_stream.rb +9 -6
  41. data/lib/cosmos/system/target.rb +3 -6
  42. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +57 -48
  43. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +7 -3
  44. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +1 -1
  45. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +7 -1
  46. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +1 -2
  47. data/lib/cosmos/top_level.rb +22 -11
  48. data/lib/cosmos/utilities/message_log.rb +14 -9
  49. data/lib/cosmos/version.rb +5 -5
  50. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +16 -16
  51. data/spec/interfaces/linc_interface_spec.rb +3 -0
  52. data/spec/interfaces/tcpip_client_interface_spec.rb +1 -0
  53. data/spec/interfaces/tcpip_server_interface_spec.rb +9 -0
  54. data/spec/io/json_drb_object_spec.rb +1 -1
  55. data/spec/io/serial_driver_spec.rb +0 -1
  56. data/spec/packet_logs/packet_log_writer_spec.rb +5 -3
  57. data/spec/packets/packet_config_spec.rb +22 -837
  58. data/spec/packets/packet_item_spec.rb +10 -10
  59. data/spec/packets/packet_spec.rb +239 -1
  60. data/spec/packets/parsers/format_string_parser_spec.rb +122 -0
  61. data/spec/packets/parsers/limits_parser_spec.rb +282 -0
  62. data/spec/packets/parsers/limits_response_parser_spec.rb +149 -0
  63. data/spec/packets/parsers/macro_parser_spec.rb +184 -0
  64. data/spec/packets/parsers/packet_item_parser_spec.rb +306 -0
  65. data/spec/packets/parsers/packet_parser_spec.rb +99 -0
  66. data/spec/packets/parsers/processor_parser_spec.rb +114 -0
  67. data/spec/packets/parsers/state_parser_spec.rb +156 -0
  68. data/spec/packets/structure_item_spec.rb +14 -14
  69. data/spec/packets/structure_spec.rb +162 -16
  70. data/spec/streams/fixed_stream_protocol_spec.rb +7 -4
  71. data/spec/streams/length_stream_protocol_spec.rb +3 -0
  72. data/spec/streams/preidentified_stream_protocol_spec.rb +3 -0
  73. data/spec/streams/serial_stream_spec.rb +12 -0
  74. data/spec/streams/stream_protocol_spec.rb +14 -0
  75. data/spec/streams/stream_spec.rb +1 -0
  76. data/spec/streams/tcpip_client_stream_spec.rb +3 -0
  77. data/spec/streams/tcpip_socket_stream_spec.rb +15 -3
  78. data/spec/streams/template_stream_protocol_spec.rb +5 -0
  79. data/spec/streams/terminated_stream_protocol_spec.rb +4 -0
  80. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +21 -1
  81. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +1 -1
  82. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +1 -1
  83. 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 >= 0 and temp_max <= @graph_right_x
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 < 0
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
- answer = Qt::InputDialog::getText(window, "Ask", question, Qt::LineEdit::Normal, "", @@qt_boolean)
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
- Logger.info "User entered '#{answer}' for '#{question}'"
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.to_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
- @socket.close if @socket and !@socket.closed?
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
- first_try = true
70
- loop do
71
- if !@socket or @socket.closed? or @request_in_progress
72
- if @request_in_progress
73
- @socket.close if @socket and !@socket.closed?
74
- @socket = nil
75
- @request_in_progress = false
76
- end
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 = TCPSocket.new(@hostname, @port)
79
- @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
80
- rescue => e
81
- raise DRb::DRbConnError, e.message
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
- request = JsonRpcRequest.new(method_name, method_params, @id)
86
- @id += 1
116
+ request = JsonRpcRequest.new(method_name, method_params, @id)
117
+ @id += 1
87
118
 
88
- request_data = request.to_json(:allow_nan => true)
89
- begin
90
- @request_in_progress = true
91
- STDOUT.puts "Request:\n" if JsonDRb.debug?
92
- STDOUT.puts request_data if JsonDRb.debug?
93
- JsonDRb.send_data(@socket, request_data)
94
- response_data = JsonDRb.receive_message(@socket, '')
95
- STDOUT.puts "\nResponse:\n" if JsonDRb.debug?
96
- STDOUT.puts response_data if JsonDRb.debug?
97
- @request_in_progress = false
98
- rescue => e
99
- @socket.close if @socket and !@socket.closed?
100
- @socket = nil
101
- if first_try
102
- first_try = false
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
- if response_data
110
- response = JsonRpcResponse.from_json(response_data)
111
- if JsonRpcErrorResponse === response
112
- if response.error.data
113
- raise Exception.from_hash(response.error.data)
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
- return response.result
141
+ raise "JsonDRb Error (#{response.error.code}): #{response.error.message}"
119
142
  end
120
143
  else
121
- # Socket was closed by server
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
- end # loop
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.to_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 = []
@@ -4,3 +4,4 @@ require 'cosmos/packet_logs/packet_log_writer'
4
4
  require 'cosmos/packet_logs/meta_packet_log_writer'
5
5
  require 'cosmos/packet_logs/packet_log_writer_pair'
6
6
  require 'cosmos/packet_logs/packet_log_reader'
7
+ require 'cosmos/packet_logs/ccsds_log_reader'
@@ -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