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
@@ -32,6 +32,7 @@ module Cosmos
32
32
  @filename = ''
33
33
  @file = nil
34
34
  @start_time = nil
35
+ @mutex = Mutex.new
35
36
  end
36
37
 
37
38
  # Ensures the log file is opened and ready to write. It then writes the
@@ -39,34 +40,38 @@ module Cosmos
39
40
  #
40
41
  # @param message [String] Message to write to the log
41
42
  def write(message)
42
- if @file.nil? or @file.closed? or (not File.exist?(@filename))
43
- start()
44
- end
43
+ @mutex.synchronize do
44
+ if @file.nil? or @file.closed? or (not File.exist?(@filename))
45
+ start(false)
46
+ end
45
47
 
46
- @file.write(message)
47
- # While it's nice to flush the IO this is an extreme slowdown
48
- #@file.flush
48
+ @file.write(message)
49
+ end
49
50
  end
50
51
 
51
52
  # Closes the message log and marks it read only
52
- def stop
53
+ def stop(take_mutex = true)
54
+ @mutex.lock if take_mutex
53
55
  if @file and not @file.closed?
54
56
  @file.close
55
57
  Cosmos.set_working_dir do
56
58
  File.chmod(0444, @filename)
57
59
  end
58
60
  end
61
+ @mutex.unlock if take_mutex
59
62
  end
60
63
 
61
64
  # Creates a new message log and sets the filename
62
- def start
65
+ def start(take_mutex = true)
66
+ @mutex.lock if take_mutex
63
67
  # Prevent starting files too fast
64
68
  sleep(0.1) until !File.exist?(File.join(@log_dir, File.build_timestamped_filename([@tool_name, 'messages'])))
65
- stop()
69
+ stop(false)
66
70
  Cosmos.set_working_dir do
67
71
  @filename = File.join(@log_dir, File.build_timestamped_filename([@tool_name, 'messages']))
68
72
  @file = File.open(@filename, 'a')
69
73
  end
74
+ @mutex.unlock if take_mutex
70
75
  end
71
76
 
72
77
  end # class MessageLog
@@ -1,12 +1,12 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- COSMOS_VERSION = '3.1.2'
3
+ COSMOS_VERSION = '3.2.0'
4
4
  module Cosmos
5
5
  module Version
6
6
  MAJOR = '3'
7
- MINOR = '1'
8
- PATCH = '2'
9
- BUILD = '5864bf4376d74014c01d625e46b5aefc843908ba'
7
+ MINOR = '2'
8
+ PATCH = '0'
9
+ BUILD = '29c04013a08ebeab57b88412820e0cd79782c49f'
10
10
  end
11
- VERSION = '3.1.2'
11
+ VERSION = '3.2.0'
12
12
  end
@@ -44,31 +44,31 @@ module Cosmos
44
44
  sleep 0.1 # Give the server time to really stop all the Threads
45
45
  end
46
46
 
47
- specify { @ctsi.methods.should include(:cmd) }
47
+ specify { expect(@ctsi.methods).to include(:cmd) }
48
48
 
49
49
  describe "connect, connected?, disconnect" do
50
- it "should subscribe to the server" do
50
+ it "subscribes to the server" do
51
51
  expect { @ctsi.connect }.to_not raise_error
52
- @ctsi.connected?.should be_truthy
52
+ expect(@ctsi.connected?).to be true
53
53
  expect { @ctsi.disconnect}.to_not raise_error
54
- @ctsi.connected?.should be_falsey
54
+ expect(@ctsi.connected?).to be false
55
55
  end
56
56
  end
57
57
 
58
58
  describe "write_raw_allowed?" do
59
- it "should be false" do
60
- @ctsi.write_raw_allowed?.should be_falsey
59
+ it "returns false" do
60
+ expect(@ctsi.write_raw_allowed?).to be false
61
61
  end
62
62
  end
63
63
 
64
64
  describe "write_raw" do
65
- it "should raise an error" do
65
+ it "raises an error" do
66
66
  expect { @ctsi.write_raw(nil) }.to raise_error(/write_raw not implemented/)
67
67
  end
68
68
  end
69
69
 
70
70
  describe "read" do
71
- it "should first return the COSMOS VERSION packet and then COSMOS LIMITS_CHANGE" do
71
+ it "returns the COSMOS VERSION packet and then COSMOS LIMITS_CHANGE" do
72
72
  @ctsi.connect
73
73
 
74
74
  pkt = Packet.new("TGT","PKT")
@@ -78,25 +78,25 @@ module Cosmos
78
78
  @cts.limits_change_callback(pkt, pi, :RED, 100, true)
79
79
 
80
80
  result = @ctsi.read
81
- result.read('CTDB').should eql "Demo Version"
81
+ expect(result.read('CTDB')).to eql "Demo Version"
82
82
 
83
83
  result = @ctsi.read
84
- result.read('TARGET').should eql "TGT"
85
- result.read('PACKET').should eql "PKT"
86
- result.read('ITEM').should eql "ITEM"
87
- result.read('OLD_STATE').should eql "RED"
88
- result.read('NEW_STATE').should eql "GREEN"
84
+ expect(result.read('TARGET')).to eql "TGT"
85
+ expect(result.read('PACKET')).to eql "PKT"
86
+ expect(result.read('ITEM')).to eql "ITEM"
87
+ expect(result.read('OLD_STATE')).to eql "RED"
88
+ expect(result.read('NEW_STATE')).to eql "GREEN"
89
89
  end
90
90
  end
91
91
 
92
92
  describe "write" do
93
- it "should raise an error if the packet is not identified" do
93
+ it "raises an error if the packet is not identified" do
94
94
  pkt = Packet.new("COSMOS","STARTLOGGING")
95
95
  pkt.buffer = "\x00\x00\x00\x00\x00\x00\x00\x00"
96
96
  expect { @ctsi.write(pkt) }.to raise_error(/Unknown command/)
97
97
  end
98
98
 
99
- it "should raise an error if the command is not recognized" do
99
+ it "raises an error if the command is not recognized" do
100
100
  pkt = Packet.new("COSMOS","DOSOMETHING")
101
101
  pkt.buffer = "\x00\x00\x00\x00\x00\x00\x00\x00"
102
102
  expect { @ctsi.write(pkt) }.to raise_error(/Unknown command/)
@@ -22,6 +22,7 @@ module Cosmos
22
22
  describe "connect" do
23
23
  it "should pass a new TcpipClientStream to the stream protocol" do
24
24
  stream = double("stream")
25
+ allow(stream).to receive(:connect)
25
26
  expect(TcpipClientStream).to receive(:new) { stream }
26
27
  expect(stream).to receive(:connected?) { true }
27
28
  expect(stream).to receive(:raw_logger_pair=) { nil }
@@ -36,6 +37,7 @@ module Cosmos
36
37
  describe "write" do
37
38
  before(:each) do
38
39
  stream = double("stream")
40
+ allow(stream).to receive(:connect)
39
41
  expect(TcpipClientStream).to receive(:new) { stream }
40
42
  allow(stream).to receive(:connected?) { true }
41
43
  allow(stream).to receive(:write)
@@ -159,6 +161,7 @@ module Cosmos
159
161
  describe "read" do
160
162
  before(:each) do
161
163
  stream = double("stream")
164
+ allow(stream).to receive(:connect)
162
165
  expect(TcpipClientStream).to receive(:new) { stream }
163
166
  allow(stream).to receive(:connected?) { true }
164
167
  allow(stream).to receive(:write)
@@ -40,6 +40,7 @@ module Cosmos
40
40
  describe "connect" do
41
41
  it "should pass a new TcpipClientStream to the stream protocol" do
42
42
  stream = double("stream")
43
+ allow(stream).to receive(:connect)
43
44
  expect(TcpipClientStream).to receive(:new) { stream }
44
45
  expect(stream).to receive(:connected?) { true }
45
46
  expect(stream).to receive(:raw_logger_pair=) { nil }
@@ -146,6 +146,15 @@ module Cosmos
146
146
  expect { i.write_raw('') }.to raise_error("TEST")
147
147
  end
148
148
  end
149
+
150
+ describe "set_option" do
151
+ it "should set the listen address for the tcpip_server" do
152
+ expect(@stream).to receive(:listen_address=).with('127.0.0.1')
153
+ i = TcpipServerInterface.new('8888','8889','5','5','burst')
154
+ i.set_option('LISTEN_ADDRESS', ['127.0.0.1'])
155
+ end
156
+ end
157
+
149
158
  end
150
159
  end
151
160
 
@@ -40,7 +40,7 @@ module Cosmos
40
40
  it "should raise an exception if the remote connection can't be made" do
41
41
  json = JsonDRb.new
42
42
  json.start_service('127.0.0.1', 7777, self)
43
- allow(TCPSocket).to receive(:new) { raise "Error" }
43
+ allow_any_instance_of(Socket).to receive(:connect_nonblock) { raise "Error" }
44
44
  obj = JsonDRbObject.new("localhost", 7777)
45
45
  expect { obj.my_method(10) }.to raise_error(DRb::DRbConnError)
46
46
  obj.disconnect
@@ -40,7 +40,6 @@ module Cosmos
40
40
 
41
41
  it "should defer to the posix serial driver on nix" do
42
42
  class PosixSerialDriver
43
- def initialize(port,baud); end
44
43
  end
45
44
  allow(Kernel).to receive(:is_windows?).and_return(false)
46
45
  driver = double("PosixSerialDriver")
@@ -130,9 +130,11 @@ module Cosmos
130
130
  Dir[File.join(@log_path,"*.bin")].length.should eql 2
131
131
  # Check that the log files have timestamps which are 3 (or 4) seconds apart
132
132
  files = Dir[File.join(@log_path,"*tlm.bin")].sort
133
- log1_seconds = files[0].split('_')[-3].to_i * 60 + files[0].split('_')[-2].to_i
134
- log2_seconds = files[1].split('_')[-3].to_i * 60 + files[1].split('_')[-2].to_i
135
- (log2_seconds - log1_seconds).should be_within(2).of(3)
133
+ split1 = files[0].split('_')
134
+ split2 = files[1].split('_')
135
+ log1_time = Time.new(split1[-7].to_i, split1[-6].to_i, split1[-5].to_i, split1[-4].to_i, split1[-3].to_i, split1[-2].to_i)
136
+ log2_time = Time.new(split2[-7].to_i, split2[-6].to_i, split2[-5].to_i, split2[-4].to_i, split2[-3].to_i, split2[-2].to_i)
137
+ (log2_time - log1_time).should be_within(2).of(3)
136
138
  plw.shutdown
137
139
  # Monkey patch the constant back to the default
138
140
  PacketLogWriter.__send__(:remove_const,:CYCLE_TIME_INTERVAL)
@@ -30,115 +30,12 @@ module Cosmos
30
30
  tf.unlink
31
31
  end
32
32
 
33
- it "should complain about overlapping items" do
34
- tf = Tempfile.new('unittest')
35
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
36
- tf.puts ' ITEM item1 0 8 UINT'
37
- tf.puts ' ITEM item2 0 8 UINT'
38
- tf.close
39
- @pc.process_file(tf.path, "TGT1")
40
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 0 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
41
- tf.unlink
42
- end
43
-
44
- it "should not complain with non-overlapping negative offsets" do
45
- tf = Tempfile.new('unittest')
46
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
47
- tf.puts ' ITEM item1 0 8 UINT'
48
- tf.puts ' ITEM item2 8 -16 BLOCK'
49
- tf.puts ' ITEM item3 -16 16 UINT'
50
- tf.close
51
- @pc.process_file(tf.path, "TGT1")
52
- @pc.warnings[0].should be_nil
53
- tf.unlink
54
- end
55
-
56
- it "should complain with overlapping negative offsets" do
57
- tf = Tempfile.new('unittest')
58
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
59
- tf.puts ' ITEM item1 0 8 UINT'
60
- tf.puts ' ITEM item2 8 -16 BLOCK'
61
- tf.puts ' ITEM item3 -17 16 UINT'
62
- tf.close
63
- @pc.process_file(tf.path, "TGT1")
64
- @pc.warnings[0].should eql "Bit definition overlap at bit offset -17 for Telemetry packet TGT1 PKT2 items ITEM3 and ITEM2"
65
- tf.unlink
66
- end
67
-
68
- it "should complain about intersecting items" do
69
- tf = Tempfile.new('unittest')
70
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
71
- tf.puts ' ITEM item1 0 32 UINT'
72
- tf.puts ' ITEM item2 16 32 UINT'
73
- tf.close
74
- @pc.process_file(tf.path, "TGT1")
75
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 16 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
76
- tf.unlink
77
- end
78
-
79
- it "should complain about array overlapping items" do
80
- tf = Tempfile.new('unittest')
81
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
82
- tf.puts ' ARRAY_ITEM item1 0 8 UINT 32'
83
- tf.puts ' ARRAY_ITEM item2 0 8 UINT 32'
84
- tf.close
85
- @pc.process_file(tf.path, "TGT1")
86
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 0 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
87
- tf.unlink
88
- end
89
-
90
- it "should not complain with array non-overlapping negative offsets" do
91
- tf = Tempfile.new('unittest')
92
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
93
- tf.puts ' ITEM item1 0 8 UINT'
94
- tf.puts ' ARRAY_ITEM item2 8 8 INT -16'
95
- tf.puts ' ITEM item3 -16 16 UINT'
96
- tf.close
97
- @pc.process_file(tf.path, "TGT1")
98
- @pc.warnings[0].should be_nil
99
- tf.unlink
100
- end
101
-
102
- it "should complain with array overlapping negative offsets" do
103
- tf = Tempfile.new('unittest')
104
- tf.puts 'TELEMETRY tgt1 pkt2 LITTLE_ENDIAN "Description"'
105
- tf.puts ' ITEM item1 0 8 UINT'
106
- tf.puts ' ARRAY_ITEM item2 8 8 INT -16'
107
- tf.puts ' ITEM item3 -17 16 UINT'
108
- tf.close
109
- @pc.process_file(tf.path, "TGT1")
110
- @pc.warnings[0].should eql "Bit definition overlap at bit offset -17 for Telemetry packet TGT1 PKT2 items ITEM3 and ITEM2"
111
- tf.unlink
112
- end
113
-
114
- it "should complain about array intersecting items" do
115
- tf = Tempfile.new('unittest')
116
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
117
- tf.puts ' ARRAY_ITEM item1 0 8 UINT 32'
118
- tf.puts ' ARRAY_ITEM item2 16 8 UINT 32'
119
- tf.close
120
- @pc.process_file(tf.path, "TGT1")
121
- @pc.warnings[0].should eql "Bit definition overlap at bit offset 16 for Telemetry packet TGT1 PKT1 items ITEM2 and ITEM1"
122
- tf.unlink
123
- end
124
-
125
- it "should not complain about nonoverlapping little endian bitfields" do
126
- tf = Tempfile.new('unittest')
127
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
128
- tf.puts ' ITEM item1 12 12 UINT'
129
- tf.puts ' ITEM item2 16 16 UINT'
130
- tf.close
131
- @pc.process_file(tf.path, "TGT1")
132
- @pc.warnings[0].should be_nil
133
- tf.unlink
134
- end
135
-
136
33
  context "with all telemetry keywords" do
137
34
  before(:all) do
138
35
  # top level keywords
139
- @top_keywords = %w(TELEMETRY SELECT_TELEMETRY LIMITS_GROUP LIMITS_GROUP_ITEM)
36
+ @top_keywords = %w(SELECT_COMMAND SELECT_TELEMETRY LIMITS_GROUP LIMITS_GROUP_ITEM)
140
37
  # Keywords that require a current packet from TELEMETRY keyword
141
- @tlm_keywords = %w(SELECT_ITEM ITEM ID_ITEM ARRAY_ITEM APPEND_ITEM APPEND_ID_ITEM APPEND_ARRAY_ITEM MACRO_APPEND_START MACRO_APPEND_END PROCESSOR META)
38
+ @tlm_keywords = %w(SELECT_ITEM ITEM ID_ITEM ARRAY_ITEM APPEND_ITEM APPEND_ID_ITEM APPEND_ARRAY_ITEM PROCESSOR META)
142
39
  # Keywords that require both a current packet and current item
143
40
  @item_keywords = %w(STATE READ_CONVERSION WRITE_CONVERSION POLY_READ_CONVERSION POLY_WRITE_CONVERSION SEG_POLY_READ_CONVERSION SEG_POLY_WRITE_CONVERSION GENERIC_READ_CONVERSION_START GENERIC_WRITE_CONVERSION_START LIMITS LIMITS_RESPONSE UNITS FORMAT_STRING DESCRIPTION META)
144
41
  end
@@ -177,7 +74,6 @@ module Cosmos
177
74
  end
178
75
 
179
76
  @tlm_keywords.each do |keyword|
180
- next if %w(MACRO_APPEND_END).include? keyword
181
77
  tf = Tempfile.new('unittest')
182
78
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
183
79
  tf.puts keyword
@@ -202,8 +98,8 @@ module Cosmos
202
98
  @top_keywords.each do |keyword|
203
99
  tf = Tempfile.new('unittest')
204
100
  case keyword
205
- when "TELEMETRY"
206
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet" extra'
101
+ when "SELECT_COMMAND"
102
+ tf.puts 'SELECT_COMMAND tgt1 pkt1 extra'
207
103
  when "SELECT_TELEMETRY"
208
104
  tf.puts 'SELECT_TELEMETRY tgt1 pkt1 extra'
209
105
  when 'LIMITS_GROUP'
@@ -217,7 +113,7 @@ module Cosmos
217
113
  end
218
114
 
219
115
  @tlm_keywords.each do |keyword|
220
- next if %w(MACRO_APPEND_END PROCESSOR META).include? keyword
116
+ next if %w(PROCESSOR META).include? keyword
221
117
  tf = Tempfile.new('unittest')
222
118
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
223
119
  case keyword
@@ -236,10 +132,6 @@ module Cosmos
236
132
  when "SELECT_ITEM"
237
133
  tf.puts 'ITEM myitem 0 8 UINT'
238
134
  tf.puts 'SELECT_ITEM myitem extra'
239
- when "MACRO_APPEND_START"
240
- tf.puts 'MACRO_APPEND_START 0 1 "%s_%d" extra'
241
- when "ACRO_APPEND_END"
242
- tf.puts 'MACRO_APPEND_END extra'
243
135
  end
244
136
  tf.close
245
137
  expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Too many parameters for #{keyword}/)
@@ -271,47 +163,6 @@ module Cosmos
271
163
  end
272
164
  end
273
165
 
274
- context "with COMMAND or TELEMETRY" do
275
- it "should complain about invalid endianness" do
276
- %w(COMMAND TELEMETRY).each do |keyword|
277
- tf = Tempfile.new('unittest')
278
- tf.puts keyword + ' tgt1 pkt1 MIDDLE_ENDIAN "Packet"'
279
- tf.close
280
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid endianness MIDDLE_ENDIAN. Must be BIG_ENDIAN or LITTLE_ENDIAN.")
281
- tf.unlink
282
- end
283
- end
284
-
285
- it "should process target, packet, endianness, description" do
286
- %w(COMMAND TELEMETRY).each do |keyword|
287
- tf = Tempfile.new('unittest')
288
- tf.puts keyword + ' tgt1 pkt1 LITTLE_ENDIAN "Packet"'
289
- tf.close
290
- @pc.process_file(tf.path, "TGT1")
291
- pkt = @pc.commands["TGT1"]["PKT1"] if keyword == 'COMMAND'
292
- pkt = @pc.telemetry["TGT1"]["PKT1"] if keyword == 'TELEMETRY'
293
- pkt.target_name.should eql "TGT1"
294
- pkt.packet_name.should eql "PKT1"
295
- pkt.default_endianness.should eql :LITTLE_ENDIAN
296
- pkt.description.should eql "Packet"
297
- tf.unlink
298
- end
299
- end
300
-
301
- it "should substitute the target name" do
302
- %w(COMMAND TELEMETRY).each do |keyword|
303
- tf = Tempfile.new('unittest')
304
- tf.puts keyword + ' tgt1 pkt1 LITTLE_ENDIAN "Packet"'
305
- tf.close
306
- @pc.process_file(tf.path, "NEW")
307
- pkt = @pc.commands["NEW"]["PKT1"] if keyword == 'COMMAND'
308
- pkt = @pc.telemetry["NEW"]["PKT1"] if keyword == 'TELEMETRY'
309
- pkt.target_name.should eql "NEW"
310
- tf.unlink
311
- end
312
- end
313
- end
314
-
315
166
  context "with SELECT_COMMAND or SELECT_TELEMETRY" do
316
167
  it "should complain if the packet is not found" do
317
168
  %w(SELECT_COMMAND SELECT_TELEMETRY).each do |keyword|
@@ -442,176 +293,21 @@ module Cosmos
442
293
  end
443
294
  end
444
295
 
445
- context "with keywords including ITEM" do
446
- it "should only allow DERIVED items with offset 0 and size 0" do
447
- tf = Tempfile.new('unittest')
448
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
449
- tf.puts ' ITEM ITEM1 8 0 DERIVED'
450
- tf.close
451
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_offset of zero/)
452
- tf.unlink
453
-
454
- tf = Tempfile.new('unittest')
455
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
456
- tf.puts ' ITEM ITEM1 0 8 DERIVED'
457
- tf.close
458
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_size of zero/)
459
- tf.unlink
460
-
296
+ context "with MACRO_APPEND" do
297
+ it "creates a range of items" do
461
298
  tf = Tempfile.new('unittest')
462
299
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
463
- tf.puts ' ITEM ITEM1 0 0 DERIVED'
464
- tf.close
465
- @pc.process_file(tf.path, "TGT1")
466
- @pc.telemetry["TGT1"]["PKT1"].items.keys.should include('ITEM1')
467
- tf.unlink
468
- end
469
-
470
- it "should accept types INT UINT FLOAT STRING BLOCK" do
471
- tf = Tempfile.new('unittest')
472
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
473
- tf.puts ' ID_ITEM ITEM1 0 32 INT 0'
474
- tf.puts ' ITEM ITEM2 0 32 UINT'
475
- tf.puts ' ARRAY_ITEM ITEM3 0 32 FLOAT 64'
476
- tf.puts ' APPEND_ID_ITEM ITEM4 32 STRING "ABCD"'
477
- tf.puts ' APPEND_ITEM ITEM5 32 BLOCK'
478
- tf.puts ' APPEND_ARRAY_ITEM ITEM6 32 BLOCK 64'
479
- tf.close
480
- @pc.process_file(tf.path, "TGT1")
481
- @pc.telemetry["TGT1"]["PKT1"].items.keys.should include('ITEM1','ITEM2','ITEM3','ITEM4','ITEM5','ITEM6')
482
- id_items = []
483
- id_items << @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]
484
- id_items << @pc.telemetry["TGT1"]["PKT1"].items["ITEM4"]
485
- @pc.telemetry["TGT1"]["PKT1"].id_items.should eql id_items
486
- tf.unlink
487
- end
488
-
489
- it "should support arbitrary endianness per item" do
490
- tf = Tempfile.new('unittest')
491
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
492
- tf.puts ' ID_ITEM ITEM1 0 32 UINT 0 "" LITTLE_ENDIAN'
493
- tf.puts ' ITEM ITEM2 0 32 UINT "" LITTLE_ENDIAN'
494
- tf.puts ' ARRAY_ITEM ITEM3 0 32 UINT 64 "" LITTLE_ENDIAN'
495
- tf.puts ' APPEND_ID_ITEM ITEM4 32 UINT 1 "" LITTLE_ENDIAN'
496
- tf.puts ' APPEND_ITEM ITEM5 32 UINT "" LITTLE_ENDIAN'
497
- tf.puts ' APPEND_ARRAY_ITEM ITEM6 32 UINT 64 "" LITTLE_ENDIAN'
498
- tf.puts ' ID_ITEM ITEM10 224 32 UINT 0 "" BIG_ENDIAN'
499
- tf.puts ' ITEM ITEM20 256 32 UINT "" BIG_ENDIAN'
500
- tf.puts ' ARRAY_ITEM ITEM30 0 32 UINT 64 "" BIG_ENDIAN'
501
- tf.puts ' APPEND_ID_ITEM ITEM40 32 UINT 1 "" BIG_ENDIAN'
502
- tf.puts ' APPEND_ITEM ITEM50 32 UINT "" BIG_ENDIAN'
503
- tf.puts ' APPEND_ARRAY_ITEM ITEM60 32 UINT 64 "" BIG_ENDIAN'
504
- tf.close
505
- @pc.process_file(tf.path, "TGT1")
506
- packet = @pc.telemetry["TGT1"]["PKT1"]
507
- packet.buffer = "\x00\x00\x00\x01" * 16
508
- packet.read("ITEM1").should eql 0x01000000
509
- packet.read("ITEM2").should eql 0x01000000
510
- packet.read("ITEM3").should eql [0x01000000, 0x01000000]
511
- packet.read("ITEM4").should eql 0x01000000
512
- packet.read("ITEM5").should eql 0x01000000
513
- packet.read("ITEM6").should eql [0x01000000, 0x01000000]
514
- packet.read("ITEM10").should eql 0x00000001
515
- packet.read("ITEM20").should eql 0x00000001
516
- packet.read("ITEM30").should eql [0x00000001, 0x00000001]
517
- packet.read("ITEM40").should eql 0x00000001
518
- packet.read("ITEM50").should eql 0x00000001
519
- packet.read("ITEM60").should eql [0x00000001, 0x00000001]
520
- tf.unlink
521
- end
522
- end
523
-
524
- context "with keywords including PARAMETER" do
525
- it "should only allow DERIVED items with offset 0 and size 0" do
526
- tf = Tempfile.new('unittest')
527
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
528
- tf.puts ' PARAMETER ITEM1 8 0 DERIVED 0 0 0'
529
- tf.close
530
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_offset of zero/)
531
- tf.unlink
532
-
533
- tf = Tempfile.new('unittest')
534
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
535
- tf.puts ' PARAMETER ITEM1 0 8 DERIVED 0 0 0'
536
- tf.close
537
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED items must have bit_size of zero/)
538
- tf.unlink
539
-
540
- tf = Tempfile.new('unittest')
541
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
542
- tf.puts ' PARAMETER ITEM1 0 0 DERIVED 0 0 0'
543
- tf.close
544
- @pc.process_file(tf.path, "TGT1")
545
- @pc.commands["TGT1"]["PKT1"].items.keys.should include('ITEM1')
546
- tf.unlink
547
- end
548
-
549
- it "should not allow ID_PARAMETER with DERIVED type" do
550
- tf = Tempfile.new('unittest')
551
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
552
- tf.puts ' ID_PARAMETER ITEM1 0 0 DERIVED 0 0 0'
553
- tf.close
554
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED data type not allowed/)
555
- tf.unlink
556
- end
557
-
558
- it "should not allow APPEND_ID_PARAMETER with DERIVED type" do
559
- tf = Tempfile.new('unittest')
560
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
561
- tf.puts ' APPEND_ID_PARAMETER ITEM1 0 DERIVED 0 0 0'
562
- tf.close
563
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /DERIVED data type not allowed/)
564
- tf.unlink
565
- end
566
-
567
- it "should accept types INT UINT FLOAT STRING BLOCK" do
568
- tf = Tempfile.new('unittest')
569
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
570
- tf.puts ' ID_PARAMETER ITEM1 0 32 INT 0 0 0'
571
- tf.puts ' ID_PARAMETER ITEM2 32 32 STRING "ABCD"'
572
- tf.puts ' PARAMETER ITEM3 64 32 UINT 0 0 0'
573
- tf.puts ' ARRAY_PARAMETER ITEM4 96 32 FLOAT 64'
574
- tf.puts ' APPEND_ID_PARAMETER ITEM5 32 UINT 0 0 0'
575
- tf.puts ' APPEND_ID_PARAMETER ITEM6 32 STRING "ABCD"'
576
- tf.puts ' APPEND_PARAMETER ITEM7 32 BLOCK "1234"'
577
- tf.puts ' APPEND_ARRAY_PARAMETER ITEM8 32 BLOCK 64'
578
- tf.close
579
- @pc.process_file(tf.path, "TGT1")
580
- @pc.commands["TGT1"]["PKT1"].items.keys.should include('ITEM1','ITEM2','ITEM3','ITEM4','ITEM5','ITEM6','ITEM7','ITEM8')
581
- tf.unlink
582
- end
583
-
584
- it "should support arbitrary endianness per item" do
585
- tf = Tempfile.new('unittest')
586
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
587
- tf.puts ' ID_PARAMETER ITEM1 0 32 UINT 0 0 0 "" LITTLE_ENDIAN'
588
- tf.puts ' PARAMETER ITEM2 0 32 UINT 0 0 0 "" LITTLE_ENDIAN'
589
- tf.puts ' ARRAY_PARAMETER ITEM3 0 32 UINT 64 "" LITTLE_ENDIAN'
590
- tf.puts ' APPEND_ID_PARAMETER ITEM4 32 UINT 0 0 0 "" LITTLE_ENDIAN'
591
- tf.puts ' APPEND_PARAMETER ITEM5 32 UINT 0 0 0 "" LITTLE_ENDIAN'
592
- tf.puts ' APPEND_ARRAY_PARAMETER ITEM6 32 UINT 64 "" LITTLE_ENDIAN'
593
- tf.puts ' ID_PARAMETER ITEM10 224 32 UINT 0 0 0 "" BIG_ENDIAN'
594
- tf.puts ' PARAMETER ITEM20 256 32 UINT 0 0 0 "" BIG_ENDIAN'
595
- tf.puts ' ARRAY_PARAMETER ITEM30 0 32 UINT 64 "" BIG_ENDIAN'
596
- tf.puts ' APPEND_ID_PARAMETER ITEM40 32 UINT 0 0 0 "" BIG_ENDIAN'
597
- tf.puts ' APPEND_PARAMETER ITEM50 32 UINT 0 0 0 "" BIG_ENDIAN'
598
- tf.puts ' APPEND_ARRAY_PARAMETER ITEM60 32 UINT 64 "" BIG_ENDIAN'
300
+ tf.puts 'MACRO_APPEND_START 1 3'
301
+ tf.puts ' APPEND_ITEM BYTE 8 UINT "Setting #x"'
302
+ tf.puts 'MACRO_APPEND_END'
599
303
  tf.close
600
304
  @pc.process_file(tf.path, "TGT1")
601
- packet = @pc.commands["TGT1"]["PKT1"]
602
- packet.buffer = "\x00\x00\x00\x01" * 16
603
- packet.read("ITEM1").should eql 0x01000000
604
- packet.read("ITEM2").should eql 0x01000000
605
- packet.read("ITEM3").should eql [0x01000000, 0x01000000]
606
- packet.read("ITEM4").should eql 0x01000000
607
- packet.read("ITEM5").should eql 0x01000000
608
- packet.read("ITEM6").should eql [0x01000000, 0x01000000]
609
- packet.read("ITEM10").should eql 0x00000001
610
- packet.read("ITEM20").should eql 0x00000001
611
- packet.read("ITEM30").should eql [0x00000001, 0x00000001]
612
- packet.read("ITEM40").should eql 0x00000001
613
- packet.read("ITEM50").should eql 0x00000001
614
- packet.read("ITEM60").should eql [0x00000001, 0x00000001]
305
+ pkt = @pc.telemetry["TGT1"]["PKT1"]
306
+ expect(pkt.items.length).to eql 6 # 3 plus the RECEIVED_XXX items
307
+ expect(pkt.items.keys).to include('BYTE1','BYTE2','BYTE3')
308
+ expect(pkt.sorted_items[3].name).to eql 'BYTE1'
309
+ expect(pkt.sorted_items[4].name).to eql 'BYTE2'
310
+ expect(pkt.sorted_items[5].name).to eql 'BYTE3'
615
311
  tf.unlink
616
312
  end
617
313
  end
@@ -651,56 +347,6 @@ module Cosmos
651
347
  end
652
348
  end
653
349
 
654
- context "with MACRO_APPEND_START" do
655
- it "should add items to the packet" do
656
- tf = Tempfile.new('unittest')
657
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
658
- tf.puts 'MACRO_APPEND_START 1 5'
659
- tf.puts 'APPEND_ITEM BIT 16 UINT "Setting #x"'
660
- tf.puts ' STATE BAD 0 RED'
661
- tf.puts ' STATE GOOD 1 GREEN'
662
- tf.puts 'MACRO_APPEND_END'
663
- tf.close
664
- @pc.process_file(tf.path, "TGT1")
665
- pkt = @pc.telemetry["TGT1"]["PKT1"]
666
- pkt.items.keys.should include('BIT1','BIT2','BIT3','BIT4','BIT5')
667
- limits_items = []
668
- pkt.items.each do |name, item|
669
- limits_items << item if name =~ /BIT/
670
- end
671
- pkt.limits_items.should eql limits_items
672
- tf.unlink
673
- end
674
-
675
- it "should array items to the packet" do
676
- tf = Tempfile.new('unittest')
677
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
678
- tf.puts 'MACRO_APPEND_START 1 5'
679
- tf.puts 'APPEND_ARRAY_ITEM BIT 16 INT 64 "Int Array Parameter"'
680
- tf.puts 'MACRO_APPEND_END'
681
- tf.close
682
- @pc.process_file(tf.path, "TGT1")
683
- pkt = @pc.telemetry["TGT1"]["PKT1"]
684
- pkt.items.keys.should include('BIT1','BIT2','BIT3','BIT4','BIT5')
685
- pkt.limits_items.should be_empty
686
- tf.unlink
687
- end
688
-
689
- it "should work with printf format strings" do
690
- tf = Tempfile.new('unittest')
691
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
692
- tf.puts 'MACRO_APPEND_START 1 5 "%d%s"'
693
- tf.puts 'APPEND_ID_ITEM BIT 16 UINT 0 "Setting #x"'
694
- tf.puts 'MACRO_APPEND_END'
695
- tf.close
696
- @pc.process_file(tf.path, "TGT1")
697
- pkt = @pc.telemetry["TGT1"]["PKT1"]
698
- pkt.items.keys.should include('1BIT','2BIT','3BIT','4BIT','5BIT')
699
- pkt.limits_items.should be_empty
700
- tf.unlink
701
- end
702
- end
703
-
704
350
  context "with ALLOW_SHORT" do
705
351
  it "should mark the packet as allowing short buffers" do
706
352
  tf = Tempfile.new('unittest')
@@ -806,106 +452,6 @@ module Cosmos
806
452
  end
807
453
  end
808
454
 
809
- context "with STATE" do
810
- it "should support STRING items" do
811
- tf = Tempfile.new('unittest')
812
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
813
- tf.puts ' APPEND_ITEM item1 128 STRING "state item"'
814
- tf.puts ' STATE FALSE "FALSE STRING"'
815
- tf.puts ' STATE TRUE "TRUE STRING"'
816
- tf.close
817
- @pc.process_file(tf.path, "TGT1")
818
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1", "TRUE STRING")
819
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql "TRUE"
820
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1", "FALSE STRING")
821
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql "FALSE"
822
- tf.unlink
823
- end
824
-
825
- it "should warn about duplicate states and replace the duplicate" do
826
- tf = Tempfile.new('unittest')
827
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
828
- tf.puts ' APPEND_PARAMETER item1 8 UINT 0 2 0 "state item"'
829
- tf.puts ' STATE FALSE 0'
830
- tf.puts ' STATE TRUE 1'
831
- tf.puts ' STATE FALSE 2'
832
- tf.close
833
- @pc.process_file(tf.path, "TGT1")
834
- @pc.warnings.should include("Duplicate state defined on line 5: STATE FALSE 2")
835
- @pc.commands["TGT1"]["PKT1"].buffer = "\x00"
836
- @pc.commands["TGT1"]["PKT1"].read("ITEM1").should eql 0
837
- @pc.commands["TGT1"]["PKT1"].buffer = "\x02"
838
- @pc.commands["TGT1"]["PKT1"].read("ITEM1").should eql "FALSE"
839
- tf.unlink
840
- end
841
-
842
- context "with telemetry" do
843
- it "should only allow GREEN YELLOW or RED" do
844
- tf = Tempfile.new('unittest')
845
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
846
- tf.puts ' APPEND_ITEM item1 8 UINT "state item"'
847
- tf.puts ' STATE WORST 1 ORANGE'
848
- tf.close
849
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Invalid state color ORANGE/)
850
- tf.unlink
851
- end
852
-
853
- it "should record the state values and colors" do
854
- tf = Tempfile.new('unittest')
855
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Description"'
856
- tf.puts ' APPEND_ITEM item1 8 UINT "state item"'
857
- tf.puts ' STATE STATE1 1 RED'
858
- tf.puts ' STATE STATE2 2 YELLOW'
859
- tf.puts ' STATE STATE3 3 GREEN'
860
- tf.puts ' STATE STATE4 4'
861
- tf.close
862
- @pc.process_file(tf.path, "TGT1")
863
- index = 1
864
- colors = [:RED, :YELLOW, :GREEN]
865
- @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"].states.each do |name,val|
866
- name.should eql "STATE#{index}"
867
- val.should eql index
868
- @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"].state_colors[name].should eql colors[index - 1]
869
-
870
- index += 1
871
- end
872
- @pc.telemetry["TGT1"]["PKT1"].limits_items.should eql [@pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]]
873
- tf.unlink
874
- end
875
- end
876
-
877
- context "with command" do
878
- it "should only allow HAZARDOUS as the third param" do
879
- tf = Tempfile.new('unittest')
880
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
881
- tf.puts ' APPEND_PARAMETER item1 8 UINT 0 0 0'
882
- tf.puts ' STATE WORST 0 RED'
883
- tf.close
884
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /HAZARDOUS expected as third parameter/)
885
- tf.unlink
886
- end
887
-
888
- it "should take HAZARDOUS and an optional description" do
889
- tf = Tempfile.new('unittest')
890
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Description"'
891
- tf.puts ' APPEND_PARAMETER item1 8 UINT 1 3 1'
892
- tf.puts ' STATE GOOD 1'
893
- tf.puts ' STATE BAD 2 HAZARDOUS'
894
- tf.puts ' STATE WORST 3 HAZARDOUS "Hazardous description"'
895
- tf.close
896
- @pc.process_file(tf.path, "TGT1")
897
- @pc.commands["TGT1"]["PKT1"].buffer = "\x01"
898
- @pc.commands["TGT1"]["PKT1"].check_limits
899
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["GOOD"].should be_nil
900
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["BAD"].should_not be_nil
901
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["WORST"].should_not be_nil
902
- @pc.commands["TGT1"]["PKT1"].items["ITEM1"].hazardous["WORST"].should eql "Hazardous description"
903
- @pc.commands["TGT1"]["PKT1"].limits_items.should be_empty
904
- tf.unlink
905
- end
906
- end
907
- end
908
-
909
455
  context "with READ_CONVERSION and WRITE_CONVERSION" do
910
456
  it "should complain about missing conversion file" do
911
457
  filename = File.join(File.dirname(__FILE__), "../test_only.rb")
@@ -993,76 +539,6 @@ module Cosmos
993
539
  end
994
540
  end
995
541
 
996
- context "with PROCESSOR" do
997
- it "should complain about missing processor file" do
998
- filename = File.join(File.dirname(__FILE__), "../test_only.rb")
999
- File.delete(filename) if File.exist?(filename)
1000
- @pc = PacketConfig.new
1001
-
1002
- tf = Tempfile.new('unittest')
1003
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1004
- tf.puts ' PROCESSOR TEST test_only.rb'
1005
- tf.close
1006
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /TestOnly class not found/)
1007
- tf.unlink
1008
- end
1009
-
1010
- it "should complain about a non Cosmos::Processor class" do
1011
- filename = File.join(File.dirname(__FILE__), "../processor1.rb")
1012
- File.open(filename, 'w') do |file|
1013
- file.puts "class Processor1"
1014
- file.puts " def call(packet,buffer)"
1015
- file.puts " end"
1016
- file.puts "end"
1017
- end
1018
- load 'processor1.rb'
1019
- File.delete(filename) if File.exist?(filename)
1020
-
1021
- tf = Tempfile.new('unittest')
1022
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1023
- tf.puts ' PROCESSOR P1 processor1.rb'
1024
- tf.close
1025
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /processor must be a Cosmos::Processor but is a Processor1/)
1026
- tf.unlink
1027
- end
1028
-
1029
- it "should parse the processor" do
1030
- filename = File.join(File.dirname(__FILE__), "../processor2.rb")
1031
- File.open(filename, 'w') do |file|
1032
- file.puts "require 'cosmos/processors/processor'"
1033
- file.puts "class Processor2 < Cosmos::Processor"
1034
- file.puts " def call(packet,buffer)"
1035
- file.puts " @results[:TEST] = 5"
1036
- file.puts " end"
1037
- file.puts "end"
1038
- end
1039
- load 'processor2.rb'
1040
-
1041
- tf = Tempfile.new('unittest')
1042
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1043
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1044
- tf.puts ' READ_CONVERSION processor_conversion.rb P2 TEST'
1045
- tf.puts ' PROCESSOR P2 processor2.rb'
1046
- tf.puts ' PROCESSOR P3 processor2.rb RAW'
1047
- tf.close
1048
- @pc.process_file(tf.path, "TGT1")
1049
- @pc.telemetry["TGT1"]["PKT1"].buffer = "\x01\x01"
1050
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1").should eql 5
1051
- tf.unlink
1052
-
1053
- File.delete(filename) if File.exist?(filename)
1054
- end
1055
-
1056
- it "should complain if applied to a command packet" do
1057
- tf = Tempfile.new('unittest')
1058
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1059
- tf.puts ' PROCESSOR P1 processor1.rb'
1060
- tf.close
1061
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "PROCESSOR only applies to telemetry packets")
1062
- tf.unlink
1063
- end
1064
- end
1065
-
1066
542
  context "with POLY_READ_CONVERSION and POLY_WRITE_CONVERSION" do
1067
543
  it "should perform a polynomial conversion" do
1068
544
  tf = Tempfile.new('unittest')
@@ -1163,313 +639,22 @@ module Cosmos
1163
639
  end
1164
640
 
1165
641
  context "with LIMITS" do
1166
- it "should complain if applied to a command PARAMETER" do
1167
- tf = Tempfile.new('unittest')
1168
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1169
- tf.puts ' APPEND_PARAMETER item1 16 UINT 0 0 0 "Item"'
1170
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 3 5'
1171
- tf.close
1172
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "LIMITS only applies to telemetry items")
1173
- tf.unlink
1174
- end
1175
-
1176
- it "should complain if the second parameter isn't a number" do
1177
- tf = Tempfile.new('unittest')
1178
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1179
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1180
- tf.puts ' LIMITS DEFAULT TRUE ENABLED 1 2 6 7 3 5'
1181
- tf.close
1182
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Ensure persistence is an integer/)
1183
- tf.unlink
1184
- end
1185
-
1186
- it "should complain if the third parameter isn't ENABLED or DISABLED" do
1187
- tf = Tempfile.new('unittest')
1188
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1189
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1190
- tf.puts ' LIMITS DEFAULT 3 TRUE 1 2 6 7 3 5'
1191
- tf.close
1192
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /Initial state must be ENABLED or DISABLED/)
1193
- tf.unlink
1194
- end
1195
-
1196
- it "should complain if the 4 limits are out of order" do
1197
- tf = Tempfile.new('unittest')
1198
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1199
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1200
- tf.puts ' LIMITS DEFAULT 3 ENABLED 2 1 3 4'
1201
- tf.close
1202
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1203
- tf.unlink
1204
-
1205
- tf = Tempfile.new('unittest')
1206
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1207
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1208
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 5 3 7'
1209
- tf.close
1210
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1211
- tf.unlink
1212
-
1213
- tf = Tempfile.new('unittest')
1214
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1215
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1216
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 5 4'
1217
- tf.close
1218
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1219
- tf.unlink
1220
-
1221
- tf = Tempfile.new('unittest')
1222
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1223
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1224
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 3 0'
1225
- tf.close
1226
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure yellow limits are within red limits.")
1227
- tf.unlink
1228
- end
1229
-
1230
- it "should complain if the 6 limits are out of order" do
1231
- tf = Tempfile.new('unittest')
1232
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1233
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1234
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 0 5'
1235
- tf.close
1236
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1237
- tf.unlink
1238
-
1239
- tf = Tempfile.new('unittest')
1240
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1241
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1242
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 3 6 7 2 5'
1243
- tf.close
1244
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1245
- tf.unlink
1246
-
1247
- tf = Tempfile.new('unittest')
1248
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1249
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1250
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 8 3 7'
1251
- tf.close
1252
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1253
- tf.unlink
1254
-
1255
- tf = Tempfile.new('unittest')
1256
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1257
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1258
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 8 3 9'
1259
- tf.close
1260
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1261
- tf.unlink
1262
-
1263
- tf = Tempfile.new('unittest')
1264
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1265
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1266
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 8 4 3'
1267
- tf.close
1268
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid limits specified. Ensure green limits are within yellow limits.")
1269
- tf.unlink
1270
- end
1271
-
1272
- it "should take 4 limits values" do
642
+ it "ensures limits sets have unique names" do
1273
643
  tf = Tempfile.new('unittest')
1274
644
  tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1275
645
  tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1276
646
  tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7'
647
+ tf.puts ' LIMITS TVAC 1 ENABLED 1 2 6 7'
648
+ tf.puts ' LIMITS DEFAULT 1 ENABLED 8 9 12 13'
1277
649
  tf.close
1278
650
  @pc.process_file(tf.path, "TGT1")
1279
651
  item = @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]
1280
- item.limits.values[:DEFAULT].should_not be_nil
1281
- @pc.telemetry["TGT1"]["PKT1"].buffer = "\x04"
1282
- @pc.telemetry["TGT1"]["PKT1"].enable_limits("ITEM1")
1283
- @pc.telemetry["TGT1"]["PKT1"].check_limits
1284
- item.limits.state.should eql :GREEN
1285
- @pc.telemetry["TGT1"]["PKT1"].limits_items.should eql [item]
1286
- tf.unlink
1287
- end
1288
-
1289
- it "should take 6 limits values" do
1290
- tf = Tempfile.new('unittest')
1291
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1292
- tf.puts ' APPEND_ITEM item1 16 UINT "Item"'
1293
- tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7 3 5'
1294
- tf.close
1295
- @pc.process_file(tf.path, "TGT1")
1296
- item = @pc.telemetry["TGT1"]["PKT1"].items["ITEM1"]
1297
- item.limits.values[:DEFAULT].should_not be_nil
652
+ expect(item.limits.values.length).to eql 2
653
+ # Verify the last defined DEFAULT limits wins
1298
654
  @pc.telemetry["TGT1"]["PKT1"].buffer = "\x04"
1299
655
  @pc.telemetry["TGT1"]["PKT1"].enable_limits("ITEM1")
1300
656
  @pc.telemetry["TGT1"]["PKT1"].check_limits
1301
- item.limits.state.should eql :BLUE
1302
- @pc.telemetry["TGT1"]["PKT1"].limits_items.should eql [item]
1303
- tf.unlink
1304
- end
1305
- end
1306
-
1307
- context "with LIMITS_RESPONSE" do
1308
- it "should complain if applied to a command PARAMETER" do
1309
- tf = Tempfile.new('unittest')
1310
- tf.puts 'COMMAND tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1311
- tf.puts ' APPEND_PARAMETER item1 16 UINT 0 0 0 "Item"'
1312
- tf.puts ' LIMITS_RESPONSE test.rb'
1313
- tf.close
1314
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "LIMITS_RESPONSE only applies to telemetry items")
1315
- tf.unlink
1316
- end
1317
-
1318
- it "should complain about missing response file" do
1319
- filename = File.join(File.dirname(__FILE__), "../test_only.rb")
1320
- File.delete(filename) if File.exist?(filename)
1321
- @pc = PacketConfig.new
1322
-
1323
- tf = Tempfile.new('unittest')
1324
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1325
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1326
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 3 5'
1327
- tf.puts ' LIMITS_RESPONSE test_only.rb'
1328
- tf.close
1329
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /TestOnly class not found/)
1330
- tf.unlink
1331
- end
1332
-
1333
- it "should complain about a non Cosmos::LimitsResponse class" do
1334
- filename = File.join(File.dirname(__FILE__), "../limits_response1.rb")
1335
- File.open(filename, 'w') do |file|
1336
- file.puts "class LimitsResponse1"
1337
- file.puts " def call(target_name, packet_name, item, old_limits_state, new_limits_state)"
1338
- file.puts " end"
1339
- file.puts "end"
1340
- end
1341
- load 'limits_response1.rb'
1342
- File.delete(filename) if File.exist?(filename)
1343
-
1344
- tf = Tempfile.new('unittest')
1345
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1346
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1347
- tf.puts ' LIMITS DEFAULT 3 ENABLED 1 2 6 7 3 5'
1348
- tf.puts ' LIMITS_RESPONSE limits_response1.rb'
1349
- tf.close
1350
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, /response must be a Cosmos::LimitsResponse but is a LimitsResponse1/)
1351
- tf.unlink
1352
- end
1353
-
1354
- it "should set the response" do
1355
- filename = File.join(File.dirname(__FILE__), "../limits_response2.rb")
1356
- File.open(filename, 'w') do |file|
1357
- file.puts "require 'cosmos/packets/limits_response'"
1358
- file.puts "class LimitsResponse2 < Cosmos::LimitsResponse"
1359
- file.puts " def call(target_name, packet_name, item, old_limits_state, new_limits_state)"
1360
- file.puts " puts \"\#{target_name} \#{packet_name} \#{item.name} \#{old_limits_state} \#{new_limits_state}\""
1361
- file.puts " end"
1362
- file.puts "end"
1363
- end
1364
- load 'limits_response2.rb'
1365
-
1366
- tf = Tempfile.new('unittest')
1367
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1368
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1369
- tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7 3 5'
1370
- tf.puts ' LIMITS_RESPONSE limits_response2.rb'
1371
- tf.close
1372
- @pc.process_file(tf.path, "TGT1")
1373
- pkt = @pc.telemetry["TGT1"]["PKT1"]
1374
- pkt.get_item("ITEM1").limits.response.class.should eql LimitsResponse2
1375
-
1376
- File.delete(filename) if File.exist?(filename)
1377
- tf.unlink
1378
- end
1379
-
1380
- it "should call the response with parameters" do
1381
- filename = File.join(File.dirname(__FILE__), "../limits_response2.rb")
1382
- File.open(filename, 'w') do |file|
1383
- file.puts "require 'cosmos/packets/limits_response'"
1384
- file.puts "class LimitsResponse2 < Cosmos::LimitsResponse"
1385
- file.puts " def initialize(val)"
1386
- file.puts " puts \"initialize: \#{val}\""
1387
- file.puts " end"
1388
- file.puts " def call(target_name, packet_name, item, old_limits_state, new_limits_state)"
1389
- file.puts " puts \"\#{target_name} \#{packet_name} \#{item.name} \#{old_limits_state} \#{new_limits_state}\""
1390
- file.puts " end"
1391
- file.puts "end"
1392
- end
1393
- load 'limits_response2.rb'
1394
-
1395
- tf = Tempfile.new('unittest')
1396
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1397
- tf.puts ' ITEM item1 0 16 INT "Integer Item"'
1398
- tf.puts ' LIMITS DEFAULT 1 ENABLED 1 2 6 7 3 5'
1399
- tf.puts ' LIMITS_RESPONSE limits_response2.rb 2'
1400
- tf.close
1401
- capture_io do |stdout|
1402
- @pc.process_file(tf.path, "TGT1")
1403
- stdout.string.should eql "initialize: 2\n"
1404
- end
1405
-
1406
- File.delete(filename) if File.exist?(filename)
1407
- tf.unlink
1408
- end
1409
- end
1410
-
1411
- context "with FORMAT_STRING" do
1412
- it "should complain about invalid format strings" do
1413
- tf = Tempfile.new('unittest')
1414
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1415
- tf.puts ' ITEM item1 0 8 INT'
1416
- tf.puts ' FORMAT_STRING "%*s"'
1417
- tf.close
1418
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid FORMAT_STRING specified for type INT: %*s")
1419
- tf.unlink
1420
-
1421
- tf = Tempfile.new('unittest')
1422
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1423
- tf.puts ' ITEM item1 0 8 STRING'
1424
- tf.puts ' FORMAT_STRING "%d"'
1425
- tf.close
1426
- expect { @pc.process_file(tf.path, "TGT1") }.to raise_error(ConfigParser::Error, "Invalid FORMAT_STRING specified for type STRING: %d")
1427
- tf.unlink
1428
- end
1429
-
1430
- it "should format integers" do
1431
- tf = Tempfile.new('unittest')
1432
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1433
- tf.puts ' ITEM item1 0 8 INT'
1434
- tf.puts ' FORMAT_STRING "d%d"'
1435
- tf.puts ' ITEM item2 0 8 UINT'
1436
- tf.puts ' FORMAT_STRING "u%u"'
1437
- tf.puts ' ITEM item3 0 8 UINT'
1438
- tf.puts ' FORMAT_STRING "0x%x"'
1439
- tf.close
1440
- @pc.process_file(tf.path, "TGT1")
1441
- @pc.telemetry["TGT1"]["PKT1"].buffer = "\x0a\x0b\x0c"
1442
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1",:FORMATTED).should eql "d10"
1443
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM2",:FORMATTED).should eql "u10"
1444
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM3",:FORMATTED).should eql "0xa"
1445
- tf.unlink
1446
- end
1447
-
1448
- it "should format floats" do
1449
- tf = Tempfile.new('unittest')
1450
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1451
- tf.puts ' ITEM item1 0 32 FLOAT'
1452
- tf.puts ' FORMAT_STRING "%3.3f"'
1453
- tf.close
1454
- @pc.process_file(tf.path, "TGT1")
1455
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1",12345.12345)
1456
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1",:FORMATTED).should eql "12345.123"
1457
- tf.unlink
1458
- end
1459
-
1460
- it "should format strings and blocks" do
1461
- tf = Tempfile.new('unittest')
1462
- tf.puts 'TELEMETRY tgt1 pkt1 LITTLE_ENDIAN "Packet"'
1463
- tf.puts ' ITEM item1 0 32 STRING'
1464
- tf.puts ' FORMAT_STRING "String: %s"'
1465
- tf.puts ' ITEM item2 0 32 BLOCK'
1466
- tf.puts ' FORMAT_STRING "Block: %s"'
1467
- tf.close
1468
- @pc.process_file(tf.path, "TGT1")
1469
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM1","HI")
1470
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM1",:FORMATTED).should eql "String: HI"
1471
- @pc.telemetry["TGT1"]["PKT1"].write("ITEM2","\x00\x01\x02\x03")
1472
- @pc.telemetry["TGT1"]["PKT1"].read("ITEM2",:FORMATTED).should eql "Block: \x00\x01\x02\x03"
657
+ item.limits.state.should eql :RED_LOW
1473
658
  tf.unlink
1474
659
  end
1475
660
  end